Skip to main content

Authorization Code grant flow

The OpenID Connect has several different client profiles and auth grant types based on whether the client is able to keep the credentials secret.

The most commonly used grant flow is the Authorisation Code Grant flow. The Authorization Code Grant flow can be used when the client is able to keep the client credentials secret. In this flow, the client is authenticated to the OpenID Provider (the onePortal platform) by using the client ID and secret. This flow is suitable for web applications with a back end, where the client credentials are kept out of reach of the users.

The code example below shows an example where the Authorization Code Grant flow is used. In a real situation this flow would be used in a web application, where the end user would be automatically redirected to the onePortal login page and after authorizing the client, the end user would be redirected back to the client application. The example uses the requests_oauthlib to facilitate the use of the OpenID Connect Provider.

    from requests_oauthlib import OAuth2Session

# Uncomment to allow use of http instead of https.
# Use http only for testing!
# import os
# os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'


# The client ID and secret obtained from the onePortal platform, replace these
CLIENT_ID = '3543289205522754'
CLIENT_SECRET = 'change_me'

# The URL where the client is redirected after a successful authentication
# Change to accommodate your setup. This should be something like https://myapp.com/after_login
REDIRECT_URI = 'https://example.com'

# The address of the OpenID Connect Provider (the onePortal platform)
host_address = 'https://fi.trivoreid.com'

# Scopes define the information that your application is requesting access to
# For a complete list of available scopes, please see $host_address/.well-known/openid-configuration
scope = ['email', 'openid', 'profile', 'phone', 'address']

oauth = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI, scope=scope)

authorization_url, state = oauth.authorization_url('%s/openid/auth' % host_address)

print('Please go to {} and authorize access.'.format(authorization_url))

authorization_response = input('Enter the full callback URL')

token = oauth.fetch_token(
'%s/openid/token' % host_address,
authorization_response=authorization_response,
client_secret=CLIENT_SECRET
)

r = oauth.get('%s/openid/userinfo' % host_address)

print(r.text)
print(r.headers)

Authorization Code grant flow with public clients

When the client is public, it, by definition, cannot securely store the client secret. Therefore the client cannot be authenticated during the access token request. This leaves the end-user vulnerable against various attacks explained in RFC 8252. Additionally the RFC 8252 describes best practices on how to configure native applications acting as a public OIDC clients.

All in all, in order to protect the end-user’s credentials, a public client must use an external user-agent (e.g. web-browser) and additionally use the Proof Key for Code Exchange (PKCE) described in RFC 7636 when requesting the access token. PKCE mitigates authorization code interception attacks, where an adversary intercepts the authorization code when it is returned by the external user-agent.

Basically the PKCE is a cryptographically random secret created by the client. When the client request the authorization code, it sends a transformed version of the secret along with the request. The request also contains information on how the transformation was done.

Transformation methods are at the moment either “plain” or “S256”. The “plain” method exists mainly for compatibility reasons and it sends the PKCE in plain text. This method offers no protection against eavesdroppers and should not be used.

The “S256” code challenge method, however, uses the following function to create the code challenge value:

code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))