fusionauth logo
search-interface-symbol
Quickstarts
API Docs
SDK
search-interface-symbol
talk to an expert
Log In
talk to an expert
Navigate to...
  • Welcome
  • Getting Started
    • Getting Started
    • 5-minute Setup Guide
      • Overview
      • Docker
      • Fast Path
      • Sandbox
    • Setup Wizard & First Login
    • Register a User and Login
    • Self-service Registration
    • Start and Stop FusionAuth
    • Core Concepts
      • Overview
      • Users
      • Roles
      • Groups
      • Registrations
      • Applications
      • Tenants
      • Identity Providers
      • Authentication/Authorization
      • Integration Points
    • Example Apps
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • PHP
      • Python
      • Ruby
    • Tutorials
      • Overview
      • Java Spring
      • Python Django
      • Ruby on Rails
  • Installation Guide
    • Overview
    • System Requirements
    • Server Layout
    • Cloud
    • Cluster
    • Docker
    • Fast Path
    • Kubernetes
      • Overview
      • Deployment Guide
      • Minikube Setup
      • Amazon EKS Setup
      • Google GKE Setup
      • Microsoft AKS Setup
    • Kickstart™
    • Homebrew
    • Marketplaces
    • Packages
    • Database
    • FusionAuth App
    • FusionAuth Search
    • Common Configuration
  • Migration Guide
    • Overview
    • General
    • Auth0
    • Keycloak
    • Amazon Cognito
    • Firebase
    • Microsoft Azure AD B2C
    • Tutorial
  • Admin Guide
    • Overview
    • Account Portal
    • Config Management
    • Editions and Features
    • Key Rotation
    • Licensing
    • Monitoring
    • Prometheus Setup
    • Proxy Setup
    • Reference
      • Overview
      • Configuration
      • CORS
      • Data Types
      • Hosted Login Pages Cookies
      • Known Limitations
      • Password Hashes
    • Releases
    • Roadmap
    • Search And FusionAuth
    • Securing
    • Switch Search Engines
    • Technical Support
    • Troubleshooting
    • Upgrading
    • WebAuthn
  • Login Methods
    • Identity Providers
      • Overview
      • Apple
      • Epic Games
      • External JWT
        • Overview
        • Example
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
        • Overview
        • Amazon Cognito
        • Azure AD
        • Discord
        • Github
        • Okta
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • SAML v2
        • Overview
        • ADFS
        • Azure AD
        • Okta
      • SAML v2 IdP Initiated
        • Overview
        • Okta
      • Xbox
    • OIDC & OAuth 2.0
      • Overview
      • Endpoints
      • Tokens
      • OAuth Modes
      • URL Validation
    • Passwordless
      • Overview
      • Magic Links
      • WebAuthn & Passkeys
    • SAML v2 IdP
      • Overview
      • Google
      • PagerDuty
      • Tableau Cloud
      • Zendesk
  • Developer Guide
    • Overview
    • API Gateways
      • Overview
      • Amazon API Gateway
      • Kong Gateway
      • ngrok Cloud Edge
    • Client Libraries & SDKs
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • Node
      • OpenAPI
      • PHP
      • Python
      • React
      • Ruby
      • Typescript
    • Events & Webhooks
      • Overview
      • Writing a Webhook
      • Securing Webhooks
      • Events
        • Overview
        • Audit Log Create
        • Event Log Create
        • JWT Public Key Update
        • JWT Refresh
        • JWT Refresh Token Revoke
        • Kickstart Success
        • Group Create
        • Group Create Complete
        • Group Delete
        • Group Delete Complete
        • Group Update
        • Group Update Complete
        • Group Member Add
        • Group Member Add Complete
        • Group Member Remove
        • Group Member Remove Complete
        • Group Member Update
        • Group Member Update Complete
        • User Action
        • User Bulk Create
        • User Create
        • User Create Complete
        • User Deactivate
        • User Delete
        • User Delete Complete
        • User Email Update
        • User Email Verified
        • User IdP Link
        • User IdP Unlink
        • User Login Failed
        • User Login Id Dup. Create
        • User Login Id Dup. Update
        • User Login New Device
        • User Login Success
        • User Login Suspicious
        • User Password Breach
        • User Password Reset Send
        • User Password Reset Start
        • User Password Reset Success
        • User Password Update
        • User Reactivate
        • User Reg. Create
        • User Reg. Create Complete
        • User Reg. Delete
        • User Reg. Delete Complete
        • User Registration Update
        • User Reg. Update Complete
        • User Reg. Verified
        • User 2FA Method Add
        • User 2FA Method Remove
        • User Update
        • User Update Complete
    • Guides
      • Overview
      • Application Specific Email Templates
      • Authentication Tokens
      • Exposing A Local Instance
      • JSON Web Tokens
      • Key Master
      • Localization and Internationalization
      • Multi-Factor Authentication
      • Multi-Tenant
      • Passwordless
      • Registration-based Email Verification
      • Searching With Elasticsearch
      • Securing Your APIs
      • Silent Mode
      • Single Sign-on
      • Two Factor (pre 1.26)
    • Integrations
      • Overview
      • CleanSpeak
      • Kafka
      • Twilio
    • Plugins
      • Overview
      • Writing a Plugin
      • Custom Password Hashing
    • User Control & Gating
      • Overview
      • Gate Unverified Users
      • Gate Unverified Registrations
      • User Account Lockout
  • Customization
    • Email & Templates
      • Overview
      • Configure Email
      • Email Templates
      • Email Variables
      • Message Templates
    • Lambdas
      • Overview
      • Apple Reconcile
      • Client Cred. JWT Populate
      • Epic Games Reconcile
      • External JWT Reconcile
      • Facebook Reconcile
      • Google Reconcile
      • HYPR Reconcile
      • JWT Populate
      • LDAP Connector Reconcile
      • LinkedIn Reconcile
      • Nintendo Reconcile
      • OpenID Connect Reconcile
      • SAML v2 Populate
      • SAML v2 Reconcile
      • SCIM Group Req. Converter
      • SCIM Group Resp. Convtr.
      • SCIM User Req. Converter
      • SCIM User Resp. Converter
      • Self-Service Registration
      • Sony PSN Reconcile
      • Steam Reconcile
      • Twitch Reconcile
      • Twitter Reconcile
      • Xbox Reconcile
    • Messengers
      • Overview
      • Generic Messenger
      • Twilio Messenger
    • Themes
      • Overview
      • Examples
      • Helpers
      • Localization
      • Template Variables
      • Kickstart Custom Theme
  • Premium Features
    • Overview
    • Advanced Registration Forms
    • Advanced Threat Detection
    • Application Specific Themes
    • Breached Password Detection
    • Connectors
      • Overview
      • Generic Connector
      • LDAP Connector
      • FusionAuth Connector
    • Entity Management
    • SCIM
      • Overview
      • Azure AD Client
      • Okta Client
      • SCIM-SDK
    • Self Service Account Mgmt
      • Overview
      • Updating User Data & Password
      • Add Two-Factor Authenticator
      • Add Two-Factor Email
      • Add Two-Factor SMS
      • Add WebAuthn Passkey
      • Customizing
      • Troubleshooting
    • WebAuthn
  • APIs
    • Overview
    • Authentication
    • Errors
    • API Explorer
    • Actioning Users
    • API Keys
    • Applications
    • Audit Logs
    • Connectors
      • Overview
      • Generic
      • LDAP
    • Consents
    • Emails
    • Entity Management
      • Overview
      • Entities
      • Entity Types
      • Grants
    • Event Logs
    • Families
    • Forms
    • Form Fields
    • Groups
    • Identity Providers
      • Overview
      • Links
      • Apple
      • External JWT
      • Epic Games
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
      • SAML v2
      • SAML v2 IdP Initiated
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • Xbox
    • Integrations
    • IP Access Control Lists
    • JWT
    • Keys
    • Lambdas
    • Login
    • Message Templates
    • Messengers
      • Overview
      • Generic
      • Twilio
    • Multi-Factor/Two Factor
    • Passwordless
    • Reactor
    • Registrations
    • Reports
    • SCIM
      • Overview
      • SCIM User
      • SCIM Group
      • SCIM EnterpriseUser
      • SCIM Service Provider Config.
    • System
    • Tenants
    • Themes
    • Users
    • User Actions
    • User Action Reasons
    • User Comments
    • WebAuthn
    • Webhooks
  • Release Notes

    Integrate Your Python Django Application With FusionAuth

    Integrate Your Python Django Application With FusionAuth

    In this tutorial, you are going to learn how to integrate a Python Django application with FusionAuth.

    Here’s a typical application login flow before integrating FusionAuth into your Python Django application.

    Login before FusionAuth.
    Login before FusionAuth.

    And here’s the same application login flow when FusionAuth is introduced.

    Login with FusionAuth.
    Login with FusionAuth.

    Prerequisites

    For this tutorial, you’ll need to have python3 and pip3 installed.

    You’ll also need Docker, since that is how you’ll install FusionAuth.

    The commands below are for macOS, but are limited to mkdir and cd, which have equivalent in Windows and linux.

    Download and Install FusionAuth

    First, make a project directory:

    
    mkdir integrate-fusionauth && cd integrate-fusionauth

    Then, install FusionAuth:

    
    curl -o docker-compose.yml https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/docker-compose.yml
    https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/docker-compose.override.yml
    curl -o .env https://raw.githubusercontent.com/FusionAuth/fusionauth-containers/master/docker/fusionauth/.env
    docker-compose up -d

    Create a User and an API Key

    Next, log into your FusionAuth instance. You’ll need to set up a user and a password, as well as accept the terms and conditions.

    Then, you’re at the FusionAuth admin UI. This lets you configure FusionAuth manually. But for this tutorial, you’re going to create an API key and then you’ll configure FusionAuth using our python client library.

    Navigate to Settings → API Keys. Click the + button to add a new API Key. Copy the value of the Key field and then save the key. It might be a value like CY1EUq2oAQrCgE7azl3A2xwG-OEwGPqLryDRBCoz-13IqyFYMn1_Udjt.

    Doing so creates an API key that can be used for any FusionAuth API call. Save that key value off as you’ll be using it later.

    Configure FusionAuth

    Next, you need to set up FusionAuth. This can be done in different ways, but we’re going to use the python client library. The below instructions use maven from the command line, but you can use the client library with an IDE of your preference as well.

    First, make a directory:

    
    mkdir setup-fusionauth && cd setup-fusionauth

    If you want, you can login to your instance and examine the new application configuration the script created for you after you are done.

    Now, cut and paste the following file into requirements.txt.

    Your FusionAuth configuration requirements file
    
    fusionauth-client==1.42.0

    Then copy and paste the following code into the setup.py file.

    
    from fusionauth.fusionauth_client import FusionAuthClient
    import os
    import sys
    
    APPLICATION_ID = "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e";
    
    #  You must supply your API key
    api_key_name = 'fusionauth_api_key'
    api_key = os.getenv(api_key_name)
    if not api_key:
      sys.exit("please set api key in the '" + api_key_name + "' environment variable")
    
    client = FusionAuthClient(api_key, 'http://localhost:9011')
    
    # set the issuer up correctly
    client_response = client.retrieve_tenants()
    if client_response.was_successful():
      tenant = client_response.success_response["tenants"][0]
    else:
      sys.exit("couldn't find tenants " + str(client_response.error_response))
    
    client_response = client.patch_tenant(tenant["id"], {"tenant": {"issuer":"http://localhost:9011"}})
    if not client_response.was_successful():
      sys.exit("couldn't update tenant "+ str(client_response.error_response))
    
    # generate RSA keypair for signing
    rsa_key_id = "356a6624-b33c-471a-b707-48bbfcfbc593"
    
    client_response = client.generate_key({"key": {"algorithm":"RS256", "name":"For PythonExampleApp", "length": 2048}}, rsa_key_id)
    if not client_response.was_successful():
      sys.exit("couldn't create RSA key "+ str(client_response.error_response))
    
    # create application
    # too much to inline it
    
    application = {}
    application["name"] = "PythonExampleApp"
    
    # configure oauth
    application["oauthConfiguration"] = {}
    application["oauthConfiguration"]["authorizedRedirectURLs"] = ["http://localhost:8000/oidc/callback/"]
    application["oauthConfiguration"]["requireRegistration"] = True
    application["oauthConfiguration"]["enabledGrants"] = ["authorization_code", "refresh_token"]
    application["oauthConfiguration"]["logoutURL"] = "http://localhost:8000/"
    application["oauthConfiguration"]["clientSecret"] = "change-this-in-production-to-be-a-real-secret"
    
    # some libraries don't support pkce, notably mozilla-django-oidc: https://github.com/mozilla/mozilla-django-oidc/issues/397
    # since we are server side and have a solid client secret, we're okay turning pkce off
    application["oauthConfiguration"]["proofKeyForCodeExchangePolicy"] = "NotRequiredWhenUsingClientAuthentication"
    
    # assign key from above to sign our tokens. This needs to be asymmetric
    application["jwtConfiguration"] = {}
    application["jwtConfiguration"]["enabled"] = True
    application["jwtConfiguration"]["accessTokenKeyId"] = rsa_key_id
    application["jwtConfiguration"]["idTokenKeyId"] = rsa_key_id
    
    client_response = client.create_application({"application": application}, APPLICATION_ID)
    if not client_response.was_successful():
      sys.exit("couldn't create application "+ str(client_response.error_response))
    
    # register user, there should be only one, so grab the first
    client_response = client.search_users_by_query({"search": {"queryString":"*"}})
    if not client_response.was_successful():
      sys.exit("couldn't find users "+ str(client_response.error_response))
    
    user = client_response.success_response["users"][0]
    
    # patch the user to make sure they have a full name, otherwise OIDC has issues
    client_response = client.patch_user(user["id"], {"user": {"fullName": user["firstName"]+" "+user["lastName"]}})
    if not client_response.was_successful():
      sys.exit("couldn't patch user "+ str(client_response.error_response))
    
    # now register the user
    client_response = client.register({"registration":{"applicationId":APPLICATION_ID}}, user["id"])
    if not client_response.was_successful():
      sys.exit("couldn't register user "+ str(client_response.error_response))

    Then, you can run the setup script. You’ll use venv to keep your workspace clean. This will create FusionAuth configuration for your Python Django application.

    
    python -m venv venv && \
    source venv/bin/activate && \
    pip install -r requirements.txt

    Now run the setup script:

    
    fusionauth_api_key=<your API key> python setup.py

    This configures FusionAuth for your Python Django application.

    Create Your Python Django Application

    Now you are going to create a Python Django application. While this section builds a simple Python Django application, you can use the same configuration to integrate your complex Python Django application with FusionAuth.

    First, make a directory:

    
    mkdir ../setup-django && cd ../setup-django

    Now, create a new requirements.txt file to include Python Django. Add the Django and mozilla-django-oidc plugins so that your requirements file looks like this:

    Your application requirements file
    
    fusionauth-client==1.42.0
    Django==3.2.15
    mozilla-django-oidc==2.0.0

    Then, re-run pip install to install these new packages

    
    pip install -r requirements.txt

    Then, create your site:

    
    django-admin startproject mysite

    Start Up The Server

    Then, open a new terminal. You’ll need to re-source your virtual environment settings:

    
    source venv/bin/activate

    Then, start your server:

    
    python mysite/manage.py runserver

    You can visit it to make sure it is running. If you need to stop it, hit control-C to do so. You can leave this running while you build out your application so that you can visit the app and see your progress.

    Create a View

    Switch back to your previous terminal window. It is going to be easier to run commands from within your mysite directory, so cd into it:

    
    cd mysite

    Create an app within your mysite project:

    
    python manage.py startapp app

    If you visit http://localhost:8000/app you’ll see an error message because you need to create a view. Make a templates directory

    
    mkdir -p app/templates/app

    And paste this HTML into the app/templates/app/authentication.html file:

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Django OAuth App</title>
    </head>
    <body>
    <div>
    Hello!
    </div>
    </body>
    </html>

    Create a urls.py file for your application, at app/urls.py, and put the following text in it:

    
    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        path('', views.index, name='index'),
    ]

    Then you have to tie the view to the template you created above by modifying app/views.py to look like:

    
    from django.shortcuts import render
    
    # Create your views here.
    from django.http import HttpResponse
    
    
    def index(request):
        return render(request, template_name='app/authentication.html')

    Then, modify mysite/settings.py. First, import the os module, changing the imports at the top of mysite/settings.py to look like:

    
    import os
    from pathlib import Path

    Then, add 'app’ to your list of installed applications. Add it to the `INSTALLED_APPS array.

    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app',
    ]

    The last change with mysite/settings.py is to update the templates variable. Look for the TEMPLATES variable and replace the DIRS field with this:

    
    'DIRS': (os.path.join(BASE_DIR, 'polls/templates'),),

    Finally you have to edit the mysite/urls.py file:

    • Add path('app/', include('app.urls')), to the urlpatterns variable in that file.

    • Change the import line: from django.urls import path to from django.urls import include, path.

    Here’s what mysite/urls.py should look like:

    
    """mysite URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/3.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import include, path
    
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('app/', include('app.urls')),
    ]

    At this point, you can visit http://localhost:8000/app and you should be greeted with the contents of the authentication.html file you created above.

    Add Authentication

    Now you are going to link up FusionAuth and add authentication to this project.

    First, modify mysite/settings.py and add mozilla_django_oidc to the list of applications. You installed this app in your environment when you updated requirements.txt.

    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app',
        'mozilla_django_oidc',
    ]

    You need to add some additional configuration for this app. Just below the INSTALLED_APPS array, add this:

    
    AUTHENTICATION_BACKENDS = (
        'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
    )
    
    # The below config is taken from fusionauth admin UI when you set up the Django application in it
    OIDC_RP_CLIENT_ID = 'e9fdb985-9173-4e01-9d73-ac2d60d1dc8e'
    OIDC_RP_CLIENT_SECRET = 'change-this-in-production-to-be-a-real-secret'
    
    OIDC_OP_AUTHORIZATION_ENDPOINT = "http://localhost:9011/oauth2/authorize"
    OIDC_OP_TOKEN_ENDPOINT = "http://localhost:9011/oauth2/token"
    OIDC_OP_USER_ENDPOINT = "http://localhost:9011/oauth2/userinfo"
    
    OIDC_RP_SCOPES = "openid profile email"
    
    OIDC_RP_SIGN_ALGO = "RS256"
    OIDC_OP_JWKS_ENDPOINT = "http://localhost:9011/.well-known/jwks.json"
    
    LOGIN_REDIRECT_URL = "http://localhost:8000/app/"
    LOGOUT_REDIRECT_URL = "http://localhost:8000/app/"

    Save the mysite/settings.py file.

    Next, update the paths to include those provided by the mozilla_django_oidc code. Here’s what mysite/urls.py should look like:

    
    """mysite URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/3.2/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  path('', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.urls import include, path
        2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import include, path
    
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('app/', include('app.urls')),
        path('oidc/', include('mozilla_django_oidc.urls')),
    ]

    Then you want to update the app/templates/app/authentication.html file to have this content:

    
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Django OAuth App</title>
    </head>
    <body>
    <div>
        {% if user.is_authenticated %}
        <p>You are signed-in! Welcome {{user.email}}</p>
        <form action="{% url 'oidc_logout' %}" method="post">
            {% csrf_token %}
            <input type="submit" value="Logout">
        </form>
        {% else %}
        <a href="{% url 'oidc_authentication_init' %}">Login</a>
        {% endif %}
    </div>
    </body>
    </html>

    Run all your migrations to make sure you have any needed database tables set up.

    
    python manage.py migrate

    You can now open up an incognito window and visit the Python Django app. Log in using the user you added in FusionAuth, and you’ll see a welcoming message.

    Feedback

    How helpful was this page?

    See a problem?

    File an issue in our docs repo

    Have a question or comment to share?

    Visit the FusionAuth community forum.

    © 2023 FusionAuth
    How-to
    Blog
    Expert Advice
    Download
    Subscribe for developer updates