Part 1 - Make a Provider in a Minute
Scenario
You want to make your own Authorization Server to issue access tokens to client applications for a certain API.
Start Your App
Browser-based clients (such as single-page apps) make cross-origin requests to your provider, which browsers restrict unless the server opts in with CORS. Install django-cors-headers alongside Django OAuth Toolkit so you can allow the origins you trust.
Create a virtualenv and install django-oauth-toolkit and django-cors-headers:
pip install django-oauth-toolkit django-cors-headers
Start a Django project, add oauth2_provider and corsheaders to the installed apps, and enable admin:
INSTALLED_APPS = [
'django.contrib.admin',
# ...
'oauth2_provider',
'corsheaders',
]
Include the Django OAuth Toolkit urls in your urls.py, choosing the urlspace you prefer. For example:
from django.urls import path, include
from oauth2_provider import urls as oauth2_urls
urlpatterns = [
path("admin", admin.site.urls),
path("o/", include(oauth2_urls)),
# ...
]
Include the CORS middleware in your settings.py. CorsMiddleware should be placed as high as
possible, especially before any middleware that can generate responses such as Django’s
CommonMiddleware or WhiteNoise’s WhiteNoiseMiddleware, otherwise it will not be able to add
the CORS headers to those responses.
MIDDLEWARE = (
# ...
'corsheaders.middleware.CorsMiddleware',
# ...
)
Then allow the origins your browser-based clients are served from:
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]
Django OAuth Toolkit sets the Access-Control-Allow-Origin header on the token endpoint
(/o/token/) itself, based on each application’s Allowed origins list, so the token endpoint
works for browser clients without this middleware. (The public OpenID Connect metadata endpoints —
discovery and JWKS — already send permissive CORS headers too.) django-cors-headers is what enables
CORS for the OIDC UserInfo endpoint (/o/userinfo/), which browser-based clients may call
cross-origin and which Django OAuth Toolkit does not CORS-enable on its own.
Include the required hidden input in your login template, registration/login.html.
The {{ next }} template context variable will be populated with the correct
redirect value. See the Django documentation
for details on using login templates.
<input type="hidden" name="next" value="{{ next }}" />
As a final step, execute the migrate command, start the internal server, and login with your credentials.
Create an OAuth2 Client Application
Before your Application can use the Authorization Server for user login, you must first register the app (also known as the Client.) Once registered, your app will be granted access to the API, subject to approval by its users.
Let’s register your application.
You need to be logged in before registration. So, go to http://localhost:8000/admin and log in. After that point your browser to http://localhost:8000/o/applications/ and add an Application instance. Client id and Client Secret are automatically generated; you have to provide the rest of the information:
User: the owner of the Application (e.g. a developer, or the currently logged in user.)
Redirect uris: Applications must register at least one redirection endpoint before using the authorization endpoint. The Authorization Server will deliver the access token to the client only if the client specifies one of the verified redirection uris. For this tutorial, paste verbatim the value https://www.getpostman.com/oauth2/callback
Allowed origins: Browser-based clients (such as a single-page app) use Cross-Origin Resource Sharing (CORS) to call the token endpoint from an origin other than their own. Provide a space-separated list of the origins allowed to do so. Django OAuth Toolkit adds the
Access-Control-Allow-Originheader to the token endpoint response for these origins itself, so no extra CORS middleware is required. If a browser client hits a CORS/origin error while exchanging the authorization code for a token, check that its origin is listed here. The origin must be in the form of “://” [ “:” ], such as https://login.mydomain.com or http://localhost:3000. Query strings and hash information are not taken into account when validating these URLs. This does not include the ‘Redirect URIs’ or ‘Post Logout Redirect URIs’, if those domains will also use the token endpoint, they must be included in this list.Client type: this value affects the security level at which some communications between the client application and the authorization server are performed. For this tutorial choose Confidential.
Authorization grant type: choose Authorization code
Name: this is the name of the client application on the server, and will be displayed on the authorization request page, where users can allow/deny access to their data.
Hash client secret: checking this hashes the client secret on save so it cannot be retrieved later. This should be unchecked if you plan to use OIDC with
HS256and want to check the tokens’ signatures using JWT. Otherwise, Django OAuth Toolkit cannot use Client Secret to sign the tokens (as it cannot be retrieved later) and the hashed value will be used when signing. This may lead to incompatibilities with some OIDC Relying Party libraries.
Take note of the Client id and the Client Secret then logout (this is needed only for testing the authorization process we’ll explain shortly)