Authorization Server

The Authorization Server provides several endpoints for temporary credentials, authorization, and issuing token credentials. When the resource owner (user) grants the authorization, this server will issue a token credential to the client.

Currently, Authlib Django implementation is using cache a lot, which means you don’t have to handle temporary credentials, timestamp and nonce yourself, they are all built-in.

To create an authorization server, only Client and Token models are required:

from your_project.models import Client, Token
from authlib.django.oauth1 import CacheAuthorizationServer

authorization_server = CacheAuthorizationServer(Client, Token)

Resource Owner

Resource Owner is the user who is using your service. A resource owner can log in your website with username/email and password, or other methods. In Django, we can use the built in contrib user:

from django.contrib.auth.models import User

Client

A client is an application making protected resource requests on behalf of the resource owner and with its authorization. It contains at least three information:

  • Client Identifier, usually called client_id
  • Client Password, usually called client_secret
  • Client RSA Public Key (if RSA-SHA1 signature method supported)

Authlib has no implementation for client model in Django. You need to implement it yourself:

from django.db import models
from django.contrib.auth.models import User
from authlib.specs.rfc5849 import ClientMixin

class Client(models.Model, ClientMixin):
    user = models.ForeignKey(User, on_delete=CASCADE)
    client_id = models.CharField(max_length=48, unique=True, db_index=True)
    client_secret = models.CharField(max_length=48, blank=True)
    default_redirect_uri = models.TextField(blank=False, default='')

    def get_default_redirect_uri(self):
        return self.default_redirect_uri

    def get_client_secret(self):
        return self.client_secret

    def get_rsa_public_key(self):
        return None

A client is registered by a user (developer) on your website. Get a deep inside with ClientMixin API reference.

Token

A token credential is used to access resource owners’ resources. Unlike OAuth 2, the token credential will not expire in OAuth 1. This token credentials are supposed to be saved into a persist database rather than a cache.

Here is an example of how it looks in Django:

from django.db import models
from django.contrib.auth.models import User
from authlib.specs.rfc5849 import TokenCredentialMixin

class Token(models.Model, TokenCredentialMixin):
    user = models.ForeignKey(User, on_delete=CASCADE)
    client_id = models.CharField(max_length=48, db_index=True)
    oauth_token = models.CharField(max_length=84, unique=True, db_index=True)
    oauth_token_secret = models.CharField(max_length=84)

    def get_oauth_token(self):
        return self.oauth_token

    def get_oauth_token_secret(self):
        return self.oauth_token_secret

Server Implementation

It is ready to create the endpoints for authorization and issuing tokens. Let’s start with the temporary credentials endpoint, which is used for clients to fetch a temporary credential:

from django.views.decorators.http import require_http_methods

@require_http_methods(["POST"])
def initiate_temporary_credential(request):
    return server.create_temporary_credential_response(request)

The endpoint for resource owner authorization. OAuth 1 Client will redirect user to this authorization page, so that resource owner can grant or deny this request:

from django.shortcuts import render

def authorize(request):
    # make sure that user is logged in for yourself
    if request.method == 'GET':
        try:
            req = server.check_authorization_request(request)
            context = {'req': req}
            return render(request, 'authorize.html', context)
        except OAuth1Error as error:
            context = {'error': error}
            return render(request, 'error.html', context)

    granted = request.POST.get('granted')
    if granted:
        grant_user = request.user
    else:
        grant_user = None

    try:
        return server.create_authorization_response(request, grant_user)
    except OAuth1Error as error:
        context = {'error': error}
        return render(request, 'error.html', context)

Then the final token endpoint. OAuth 1 Client will use the given temporary credential and the oauth_verifier authorized by resource owner to exchange the token credential:

from django.views.decorators.http import require_http_methods

@require_http_methods(["POST"])
def issue_token(request):
    return server.create_token_response(request)

At last, you need to register these views into url patterns.