Extending django-oauth-toolkit | Part 2

NOTE: You can read here the first part of this blog post.

In the past blog post we learned how to extend the ApplicationModel from Django-oauth-toolkit now we need to do a few extra things to get this done.

If you have extended the model properly you'll see that the Application creation form stays the same as before:

Oauth Form

It's not taking our new added fields, and that's due to this definition in the ApplicationRegistration view, on the get_form_class method they define the follow:

def get_form_class(self):
    """
    Returns the form class for the application model
    """
    return modelform_factory(
        get_application_model(),
        fields=(
            "name",
            "client_id",
            "client_secret",
            "client_type",
            "authorization_grant_type",
            "redirect_uris",
        )
    )

This means that it doesn't matter how many new fields we add to our new model, it will always render the same fields, to make this work we need to override that class and the URL, which look like this:

from oauth2_provider.views.application import (
    ApplicationRegistration, ApplicationUpdate,
)


class OAuthApplicationCreate(ApplicationRegistration):
    def get_form_class(self):
        return forms.OAuthApplicationForm

    def form_valid(self, form):
        form.instance.user = self.request.user
        form.instance.organization = self.request.organization
        return super().form_valid(form)


class OAuthApplicationUpdate(ApplicationUpdate):
    def get_form_class(self):
        return forms.OAuthApplicationForm

And your form, could be the normal ModelForm in Django, like this:

class OAuthApplicationForm(forms.ModelForm):
    scopes = forms.MultipleChoiceField(
        choices=[], widget=Select2MultipleWidget()
    )

    class Meta:
        model = models.MyApplication
        fields = (
            'name',
            'logo',
            'scopes',
            'client_type',
            'authorization_grant_type',
            'redirect_uris',
        )

Now we need to override the URL that load the ApplicationRegisterView, there's no easy form to do that like a value in Django-settings we'll use a basic concept from the Django URL Engine. In the django-oauth-toolkit docs we need to update our URLs to include the ones from OAuth-Toolkit like this:

urlpatterns = [
    ...
    path('oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')),
    ...
]

We'll add a new url that match one path from the include, the URL engine in Django will catch the first occurrence in the URLs list, and when that happens we want that this first occurrence be our custom ApplicationView for that reason we need to declare our new URL before the OAuth-Toolkit include:

from .views import (
    OAuthApplicationRegister, OAuthApplicationUpdate,
)


urlpatterns = [
    ...
    path('oauth/applications/register/', OAuthApplicationRegister.as_view()),
    path(
        'oauth/applications/<int:pk>/update/', OAuthApplicationUpdate.as_view()
    ),
    path(
        'oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')
    ),
    ...
]

And now Django instead of loading the ApplicationView from OAuth-Toolkit it will load our custom ApplicationView with our custom form that contains the new fields.

Final Oauth Form

You need to do the same for the AuthorizationView because this view loads all the scopes defined in the settings or you can create a custom oauth2-backend-class.

Custom Scopes

And that's all for now, hope you liked this post.