├── .env.example
├── .github
├── dependabot.yml
└── workflows
│ └── django.yml
├── .gitignore
├── .mergify.yml
├── .pre-commit-config.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── account_security
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
├── api_key.png
├── clients
└── twilio_client.py
├── docker-compose.yml
├── manage.py
├── phone_verification
├── __init__.py
├── apps.py
├── forms.py
├── templates
│ ├── phone_verification.html
│ ├── token_validation.html
│ └── verified.html
├── tests.py
└── views.py
├── requirements-dev.txt
├── requirements.txt
├── static
├── favicon-16x16.png
├── favicon-32x32.png
└── favicon.ico
└── twofa
├── __init__.py
├── apps.py
├── decorators.py
├── forms.py
├── managers.py
├── migrations
├── 0001_initial.py
└── __init__.py
├── models.py
├── templates
├── 2fa.html
├── base.html
├── home.html
├── protected.html
├── register.html
└── registration
│ └── login.html
├── tests.py
└── views.py
/.env.example:
--------------------------------------------------------------------------------
1 | # You can get/create one here :
2 | # https://www.twilio.com/console/authy/applications
3 | ACCOUNT_SECURITY_API_KEY='ENTER_SECRET_HERE'
4 |
5 | # Twilio API credentials
6 | # (find here https://www.twilio.com/console)
7 | TWILIO_ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8 | TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
9 |
10 | # Verification Service SID
11 | # (create one here https://www.twilio.com/console/verify/services)
12 | TWILIO_VERIFICATION_SID=VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: pip
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 | ignore:
9 | - dependency-name: pre-commit
10 | versions:
11 | - 2.10.0
12 |
--------------------------------------------------------------------------------
/.github/workflows/django.yml:
--------------------------------------------------------------------------------
1 | name: Django
2 |
3 | on:
4 | push:
5 | branches: [ master, next ]
6 | pull_request:
7 | branches: [ master, next ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ${{ matrix.platform }}
13 | strategy:
14 | max-parallel: 4
15 | matrix:
16 | python-version: [3.6, 3.7, 3.8]
17 | platform: [windows-latest, macos-latest, ubuntu-latest]
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Set up Python ${{ matrix.python-version }}
22 | uses: actions/setup-python@v1
23 | with:
24 | python-version: ${{ matrix.python-version }}
25 | - name: Install Dependencies
26 | run: |
27 | python -m pip install --upgrade pip
28 | pip install -r requirements.txt
29 | - name: Set up project
30 | run: |
31 | cp .env.example .env
32 | python manage.py migrate
33 | - name: Run Tests
34 | run: |
35 | python manage.py test
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Environment variables
2 | .env
3 |
4 | # virtualenv
5 | venv
6 |
7 | # Byte-compiled / optimized / DLL files
8 | __pycache__/
9 | *.py[cod]
10 |
11 | # Distribution / packaging
12 | .Python
13 | env/
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .coverage
43 | .coverage.*
44 | .cache
45 | nosetests.xml
46 | coverage.xml
47 | *,cover
48 |
49 | # Django stuff:
50 | *.log
51 | db.sqlite3
52 |
53 | .vscode
54 | .tool-versions
55 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | pull_request_rules:
2 | - name: automatic merge for Dependabot pull requests
3 | conditions:
4 | - author=dependabot-preview[bot]
5 | - status-success=build (3.6, macos-latest)
6 | - status-success=build (3.7, macos-latest)
7 | - status-success=build (3.8, macos-latest)
8 | - status-success=build (3.6, windows-latest)
9 | - status-success=build (3.7, windows-latest)
10 | - status-success=build (3.8, windows-latest)
11 | - status-success=build (3.6, ubuntu-latest)
12 | - status-success=build (3.7, ubuntu-latest)
13 | - status-success=build (3.8, ubuntu-latest)
14 | actions:
15 | merge:
16 | method: squash
17 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | - repo: git@github.com:pre-commit/pre-commit-hooks
2 | sha: e718847ccbc65cd72a89fefb4db61c55ec4d430d
3 | hooks:
4 | - id: trailing-whitespace
5 | exclude: \.html$
6 | - id: end-of-file-fixer
7 | exclude: \.html$
8 | - id: autopep8-wrapper
9 | args: ['-i', '--ignore=E309,E501']
10 | - id: check-json
11 | - id: check-yaml
12 | - id: debug-statements
13 | - id: requirements-txt-fixer
14 | - id: flake8
15 | exclude: >
16 | (?x)^(
17 | .*\/migrations\/.*|
18 | account_security/settings.py
19 | )$
20 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at open-source@twilio.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Twilio
2 |
3 | All third party contributors acknowledge that any contributions they provide will be made under the same open source license that the open source project is provided under.
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8
2 |
3 | ENV PYTHONUNBUFFERED 1
4 |
5 | WORKDIR /usr/src/app
6 |
7 | COPY requirements.txt ./
8 |
9 | RUN pip3 install -r requirements.txt
10 |
11 | COPY . .
12 |
13 | RUN python3 manage.py migrate
14 |
15 | EXPOSE 8000
16 |
17 | CMD ["sh", "-c", "python3 manage.py runserver 0.0.0.0:8000"]
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Twilio Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: venv install serve-setup serve
2 | UNAME := $(shell uname)
3 | venv:
4 | ifeq ($(UNAME), Windows)
5 | py -3 -m venv venv;
6 | else
7 | python3 -m venv venv
8 | endif
9 | install: venv
10 | ifeq ($(UNAME), Windows)
11 | venv\Scripts\activate.bat; \
12 | pip3 install -r requirements.txt;
13 | else
14 | . venv/bin/activate; \
15 | pip3 install -r requirements.txt;
16 | endif
17 |
18 | serve-setup:
19 | . venv/bin/activate; \
20 | python3 manage.py migrate;
21 |
22 | serve:
23 | . venv/bin/activate; \
24 | python3 manage.py runserver 0.0.0.0:8000;
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Twilio Account Security Quickstart - Two-Factor Authentication and Phone Verification
6 |
7 | 
8 |
9 | > This template is part of Twilio CodeExchange. If you encounter any issues with this code, please open an issue at [github.com/twilio-labs/code-exchange/issues](https://github.com/twilio-labs/code-exchange/issues).
10 |
11 | ## About
12 |
13 | A simple Python and Django implementation of a website that uses Twilio Account Security services to protect all assets within a folder. Additionally, it shows a Phone Verification implementation.
14 |
15 | It uses four channels for delivery: SMS, Voice, Soft Tokens, and Push Notifications. You should have the [Authy App](https://authy.com/download/) installed to try Soft Token and Push Notification support.
16 |
17 | Learn more about Account Security and when to use the Authy API vs the Verify API in the [Account Security documentation](https://www.twilio.com/docs/verify/authy-vs-verify).
18 |
19 | Implementations in other languages:
20 |
21 | | .NET | Java | Node | PHP | Ruby |
22 | | :--- | :--- | :----- | :-- | :--- |
23 | | TBD | [Done](https://github.com/TwilioDevEd/account-security-quickstart-spring) | [Done](https://github.com/TwilioDevEd/account-security-quickstart-node) | [Done](https://github.com/TwilioDevEd/account-security-quickstart-php) | [Done](https://github.com/TwilioDevEd/account-security-quickstart-rails) |
24 |
25 | ## Features
26 |
27 | #### Two-Factor Authentication Demo
28 | - URL path "/protected" is protected with both user session and Twilio Two-Factor Authentication
29 | - One Time Passwords (SMS and Voice)
30 | - SoftTokens
31 | - Push Notifications (via polling)
32 |
33 | #### Phone Verification
34 | - Phone Verification
35 | - SMS or Voice Call
36 |
37 | ## Set up
38 |
39 | ### Requirements
40 | - This project only runs on Python 3.6+. In some environments when both version 2
41 | and 3 are installed, you may substitute the Python executables below with
42 | `python3` and `pip3` unless you use a version manager such as
43 | [pyenv](https://github.com/pyenv/pyenv).
44 |
45 | ### Twilio Account Settings
46 |
47 | This application should give you a ready-made starting point for writing your own application.
48 | Before we begin, we need to collect all the config values we need to run the application:
49 |
50 | | Config Value | Description |
51 | | :---------- | :---------- |
52 | | ACCOUNT_SECURITY_API_KEY | Create a new Authy application in the [console](https://www.twilio.com/console/authy/). After you give it a name you can view the generated Account Security production API key. This is the string you will later need to set up in your environmental variables.|
53 |
54 | 
55 |
56 | ### Local Development
57 |
58 | 1. Clone this repo and `cd` into it.
59 |
60 | ```bash
61 | git clone https://github.com/TwilioDevEd/account-security-quickstart-django.git
62 | cd account-security-quickstart-django
63 | ```
64 |
65 | 2. Create the virtual environment, load it and install dependencies.
66 |
67 | ```bash
68 | make install
69 | ```
70 |
71 | 3. Set your environment variables. Copy the `env.example` file and edit it.
72 |
73 | ```bash
74 | cp .env.example .env
75 | ```
76 |
77 | See [Twilio Account Settings](#twilio-account-settings) to locate the necessary environment variables.
78 |
79 | 4. Run migrations.
80 |
81 | ```bash
82 | make serve-setup
83 | ```
84 |
85 | 5. Start the development server. Before running the following command, make sure the virtual environment is activated.
86 |
87 | ```bash
88 | make serve
89 | ```
90 |
91 | 6. The application should now be running on http://localhost:8000/, here you can
92 | register a new user account and proceed with a phone verification.
93 |
94 | That's it!
95 |
96 | ### Docker
97 |
98 | If you have [Docker](https://www.docker.com/) already installed on your machine, you can use our `docker-compose.yml` to setup your project.
99 |
100 | 1. Make sure you have the project cloned.
101 | 2. Setup the `.env` file as outlined in the [Local Development](#local-development) steps.
102 | 3. Run `docker-compose up`.
103 |
104 | ### Tests
105 |
106 | You can run the tests locally by typing the following command, make sure the virtual environment is activated.
107 |
108 | ```bash
109 | python3 manage.py test
110 | ```
111 |
112 |
113 | ### Cloud deployment
114 |
115 | Additionally to trying out this application locally, you can deploy it to a variety of host services. Here is a small selection of them.
116 |
117 | Please be aware that some of these might charge you for the usage or might make the source code for this application visible to the public. When in doubt research the respective hosting service first.
118 |
119 | | Service | |
120 | | :-------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
121 | | [Heroku](https://www.heroku.com/) | [](https://heroku.com/deploy) |
122 |
123 | ## Resources
124 |
125 | - The CodeExchange repository can be found [here](https://github.com/twilio-labs/code-exchange/).
126 |
127 | ## Contributing
128 |
129 | This template is open source and welcomes contributions. All contributions are subject to our [Code of Conduct](https://github.com/twilio-labs/.github/blob/master/CODE_OF_CONDUCT.md).
130 |
131 | ## License
132 |
133 | [MIT](http://www.opensource.org/licenses/mit-license.html)
134 |
135 | ## Disclaimer
136 |
137 | No warranty expressed or implied. Software is as is.
138 |
139 | [twilio]: https://www.twilio.com
140 |
--------------------------------------------------------------------------------
/account_security/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwilioDevEd/account-security-quickstart-django/e0c2b15e35beef640b31e1691d8f0d50eba26866/account_security/__init__.py
--------------------------------------------------------------------------------
/account_security/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for account_security project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.11.6.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.11/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.11/ref/settings/
11 | """
12 |
13 | import os
14 | from dotenv import load_dotenv
15 |
16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 |
19 | load_dotenv(os.path.join(BASE_DIR, '.env'))
20 |
21 |
22 | # Quick-start development settings - unsuitable for production
23 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
24 |
25 | # SECURITY WARNING: keep the secret key used in production secret!
26 | SECRET_KEY = '!@v)i0w+*@ld2tsr#l-e6-zp$a(k*%qt68+ago0i(yn6z9g35_'
27 |
28 | # SECURITY WARNING: don't run with debug turned on in production!
29 | DEBUG = True
30 |
31 | ALLOWED_HOSTS = []
32 |
33 |
34 | # Application definition
35 |
36 | INSTALLED_APPS = [
37 | 'django.contrib.admin',
38 | 'django.contrib.auth',
39 | 'django.contrib.contenttypes',
40 | 'django.contrib.sessions',
41 | 'django.contrib.messages',
42 | 'django.contrib.staticfiles',
43 |
44 | 'twofa',
45 | 'phone_verification',
46 | 'clients'
47 | ]
48 |
49 | MIDDLEWARE = [
50 | 'django.middleware.security.SecurityMiddleware',
51 | 'django.contrib.sessions.middleware.SessionMiddleware',
52 | 'django.middleware.common.CommonMiddleware',
53 | 'django.middleware.csrf.CsrfViewMiddleware',
54 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
55 | 'django.contrib.messages.middleware.MessageMiddleware',
56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
57 | ]
58 |
59 | ROOT_URLCONF = 'account_security.urls'
60 |
61 | TEMPLATES = [
62 | {
63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
64 | 'DIRS': [],
65 | 'APP_DIRS': True,
66 | 'OPTIONS': {
67 | 'context_processors': [
68 | 'django.template.context_processors.debug',
69 | 'django.template.context_processors.request',
70 | 'django.contrib.auth.context_processors.auth',
71 | 'django.contrib.messages.context_processors.messages',
72 | ],
73 | },
74 | },
75 | ]
76 |
77 | WSGI_APPLICATION = 'account_security.wsgi.application'
78 |
79 |
80 | # Database
81 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
82 |
83 | DATABASES = {
84 | 'default': {
85 | 'ENGINE': 'django.db.backends.sqlite3',
86 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
87 | }
88 | }
89 |
90 |
91 | # Password validation
92 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
93 |
94 | AUTH_PASSWORD_VALIDATORS = [
95 | {
96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
97 | },
98 | {
99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
100 | },
101 | {
102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
103 | },
104 | {
105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
106 | },
107 | ]
108 |
109 |
110 | # Internationalization
111 | # https://docs.djangoproject.com/en/1.11/topics/i18n/
112 |
113 | LANGUAGE_CODE = 'en-us'
114 |
115 | TIME_ZONE = 'UTC'
116 |
117 | USE_I18N = True
118 |
119 | USE_L10N = True
120 |
121 | USE_TZ = True
122 |
123 | LOGIN_URL = '/login/'
124 | LOGOUT_URL = '/logout/'
125 | LOGIN_REDIRECT_URL = '/protected/'
126 | LOGOUT_REDIRECT_URL = '/login/'
127 |
128 | # Static files (CSS, JavaScript, Images)
129 | # https://docs.djangoproject.com/en/1.11/howto/static-files/
130 |
131 | STATIC_URL = '/static/'
132 | STATIC_ROOT = os.path.join(BASE_DIR, 'static')
133 |
134 |
135 | # Use our custom User Model
136 | AUTH_USER_MODEL = 'twofa.TwoFAUser'
137 |
138 | # Authy Application Key
139 | ACCOUNT_SECURITY_API_KEY = os.environ.get('ACCOUNT_SECURITY_API_KEY')
140 | TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID')
141 | TWILIO_AUTH_TOKEN = os.environ.get('TWILIO_AUTH_TOKEN')
142 | TWILIO_VERIFICATION_SID = os.environ.get('TWILIO_VERIFICATION_SID')
143 |
--------------------------------------------------------------------------------
/account_security/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.urls import path
3 | from django.conf.urls.static import static
4 | from django.contrib.auth import views as auth_views
5 |
6 | from twofa import views as twofa_views
7 | from phone_verification import views as verify_views
8 |
9 | urlpatterns = [
10 | path('login/', auth_views.LoginView.as_view(), name='login'),
11 | path('logout/', auth_views.LogoutView.as_view(), name='logout'),
12 |
13 | path('register/', twofa_views.register, name='register'),
14 | path('2fa/', twofa_views.twofa, name='2fa'),
15 | path('token/sms', twofa_views.token_sms, name='token-sms'),
16 | path('token/voice', twofa_views.token_voice, name='token-voice'),
17 | path('token/onetouch', twofa_views.token_onetouch, name='token-onetouch'), # noqa: E501
18 | path('protected/', twofa_views.protected, name='protected'),
19 | path('onetouch-status', twofa_views.onetouch_status, name='onetouch-status'), # noqa: E501
20 |
21 | path('verification/', verify_views.phone_verification, name='phone_verification'), # noqa: E501
22 | path('verification/token/', verify_views.token_validation, name='token_validation'), # noqa: E501
23 | path('verified/', verify_views.verified, name='verified'),
24 |
25 | path('', twofa_views.home, name='home'),
26 | ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
27 |
--------------------------------------------------------------------------------
/account_security/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for account_security project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "account_security.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/api_key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwilioDevEd/account-security-quickstart-django/e0c2b15e35beef640b31e1691d8f0d50eba26866/api_key.png
--------------------------------------------------------------------------------
/clients/twilio_client.py:
--------------------------------------------------------------------------------
1 | from twilio.rest import Client
2 | from django.conf import settings
3 |
4 | client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN)
5 |
6 | def verifications(phone_number, via):
7 | return client.verify \
8 | .services(settings.TWILIO_VERIFICATION_SID) \
9 | .verifications \
10 | .create(to=phone_number, channel=via)
11 |
12 | def verification_checks(phone_number, token):
13 | return client.verify \
14 | .services(settings.TWILIO_VERIFICATION_SID) \
15 | .verification_checks \
16 | .create(to=phone_number, code=token)
17 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.8"
2 | services:
3 | app:
4 | build: .
5 | ports:
6 | - "8000:8000"
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE",
7 | "account_security.settings")
8 | try:
9 | from django.core.management import execute_from_command_line
10 | except ImportError:
11 | # The above import may fail for some other reason. Ensure that the
12 | # issue is really that Django is missing to avoid masking other
13 | # exceptions on Python 2.
14 | try:
15 | import django # noqa: F401
16 | except ImportError:
17 | raise ImportError(
18 | "Couldn't import Django. Are you sure it's installed and "
19 | "available on your PYTHONPATH environment variable? Did you "
20 | "forget to activate a virtual environment?"
21 | )
22 | raise
23 | execute_from_command_line(sys.argv)
24 |
--------------------------------------------------------------------------------
/phone_verification/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TwilioDevEd/account-security-quickstart-django/e0c2b15e35beef640b31e1691d8f0d50eba26866/phone_verification/__init__.py
--------------------------------------------------------------------------------
/phone_verification/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PhoneVerificationConfig(AppConfig):
5 | name = 'phone_verification'
6 |
--------------------------------------------------------------------------------
/phone_verification/forms.py:
--------------------------------------------------------------------------------
1 | import phonenumbers
2 |
3 | from django import forms
4 | from phonenumbers import NumberParseException
5 | from twofa.forms import BootstrapInput
6 |
7 |
8 | class BootstrapSelect(forms.Select):
9 | def __init__(self, size=12, *args, **kwargs):
10 | self.size = size
11 | super(BootstrapSelect, self).__init__(attrs={
12 | 'class': 'form-control input-sm',
13 | })
14 |
15 | def bootwrap_input(self, input_tag):
16 | classes = 'col-xs-{n} col-sm-{n} col-md-{n}'.format(n=self.size)
17 |
18 | return '''
14 | Congratulations. You have verified your Phone! 15 |
16 |14 | Implementations of both Verify Phone Verification and Authy Two-Factor Authentication 15 |
16 |14 | Congrats! You have successfully implemented Twilio Two-Factor Authentication. Browse the links below for more information related to Twilio Account Security. 15 |
16 | 17 |