Month: July 2020

Using django-oauth-toolkit for Client credentials Oauth Flow

I've been wanting to secure my api - so unidentified and unathorized parties cannot view, update, create or delete data.
This api is internal to the company and will only be used by other services - in other words no end users.
Hence the delegation of authorization need not happen and the services will be authneticating directly with the api.

That is why the Oauth client credentials flow is used - it is for server to server communication. (As far as I know)

There is alot of conflicting information on Oauth but in the RFC6749 on Oauth 2 Client credentials is mentioned:

1.3.4.  Client Credentials

   The client credentials (or other forms of client authentication) can
   be used as an authorization grant when the authorization scope is
   limited to the protected resources under the control of the client,
   or to protected resources previously arranged with the authorization
   server.  Client credentials are used as an authorization grant
   typically when the client is acting on its own behalf (the client is
   also the resource owner) or is requesting access to protected
   resources based on an authorization previously arranged with the
   authorization server.

Nordic API's: Securing the API Stronghold book mentions:

Oauth: It’s for delegation, and delegation only

I agree except when the client is the resource owner in the client credentials instance.
In that case surely there is no delegation?

Should we use it

What is the advantage over a basic auth or token authentication method?

It seems to just be an added step for the client but the key is that the token expires. So if a bad actor gets our token it will not last long before it is of no use.
The client id and secret is the thing that is used to generate tokend for future calling of the api.

Difference between Resource Owner Password Based flow and client Credentials

Django-oauth-tollkit provides both and their example uses the resource owner password based flow.
In both cases the resource owner is the client - so there is no delegation.

So what is the difference?

I checked on stackoverflow, and it turns out I was wrong.

In the resource owner client based way, the resource owner (end user) trusts the client application enough to give it it's username and password.
We don't really want this.

Implementing Client Credentials flow

Since users are not going to use the API and only services/clients will, I want to disable the other authorization flows and disable registering of clients.

I will manage the clients and they will be the resource owners.

So if you follow the information in the django-oauth-toolkit and setting it up for client credentials that should help

Permissions are significantly different from Django Permissions

What I found out durinng testing is that OauthToolkit implements it's own seperate permissions. So if you were wanting to use django model permissions (add, change, view and delete), you don't be able to.

Wait...I spoke too fast.

You can allow this with:

permission_classes = [IsAuthenticatedOrTokenHasScope, DjangoModelPermission]

However that means that you actually have to test with scopes if you expect a client to use it with Oauth and not django auth.

This is the view to use ClientProtectedResourceView

Minio uses the OAuth 2.0 Implicit flow to Auth with OpenIDC

Minio's web application is a single apge application.

As far as I can tell it is frontend only and works like a single page application.

That is why when setting up the the client for minio on keycloak.
We set implicit flow to True.

In that case there is no authorization code - and no client secret.
After auth the access token is sent to minio on the front channel. Still need to verify this happens in querystring.
Implicit flow was designed for frontend only single page applications and hence no back channel request can be made.

The client does not go through the extra backchannel step of echanging the authorization code for the access token by authenticating with the client id.

Using Keycloak as the identity provider for users on django and django-admin

I have used mozilla's Django OpenID Connect client before, but this time I found something called Django-AllAuth.

Django-Allauth seems packed full of features and is well maintained. So I am going to test whether I can use it with Keycloak as the identity provider for users on django and django admin.

Initial Setup

With your activated environment and existing django project:

pip install django-allauth

Add the required settings in settings.py:

AUTHENTICATION_BACKENDS = [
    ...
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',
    ...
]

INSTALLED_APPS = [
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.keycloak',
]

SITE_ID = 1

# Set your keycloak url and realm
SOCIALACCOUNT_PROVIDERS = {
    'keycloak': {
        'KEYCLOAK_URL': 'https://keycloak.custom/auth',
        'KEYCLOAK_REALM': 'master'
    }
}

To get the KEYCLOAK_URL you just add /auth to your keycloak base url.

In urls.py:

urlpatterns = [
    ...
    path('accounts/', include('allauth.urls')),
    ...
]

Then migrate the db:

./manage.py migrate

Following the instructions for registering a client on keycloak.

create-allauth-client-keycloak

Set the valid redirect url for development: http://localhost:8000/accounts/keycloak/login/callback/

set-the-callback-url-keycloak-allauth

Set the client as confidential

set-confidential-keycloak-allauth

Get the client id and secret

view-client-secret-allauth-keycloak

Then run the server and:

  1. Change the domain of the default site to your own
  2. Create a socialapp for each integration

That is where you add your keycloak client information.

Set the details on django admin side

create-all-auth-client-keycloak

Make sure to link it to the given site.Otherwise you will get an error like this: Django: SocialApp matching query does not exist

You can also use the settings configuration instead of adding details in the database

Trying it out

Log out of the admin and now do to:

http://127.0.0.1:8000/accounts/login/

Click Login with keycloak and login. It's not much to look at but functionality is key.

keycloak-all-auth-login

Once you are logged in it goes to the /accounts/profile path and 404's.

If you get a redirect_url error make sure you whitelist the redirect url you are using.

Fixing the Account/Profile 404

Why does it redirect here after a successful login - must I implement the view?

What happens on the admin side?

An active user is created.

How can groups / roles be pulled through from the user roles or client roles on keycloak?