The Authorization Code Grant is the most common authorization flow in OAuth2. It is a three-legged process which is considered to be the OAuth2 flow to use for best security, both with confidential and public clients (then using the PKCE Extension).
The flow works like this in short words:
?code=(authorization code)
).The calling application must redirect to the correct Authorization Server /authorize
end point.
The URL of this endpoint depends on the authentication method, and on the API. The URL is displayed
for each supported Authentication Method at the top of each API page.
https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/authorize?client_id=(your client id)&redirect_uri=(redirect URI of your application)&response_type=code&scope=(space separated list of scopes)
All parameteters except the scope and redirect URI (depending on the API) are mandatory. The correct URL for valid combinations of API and Authentication Method can be seen on the API page.
Note the use of response_type=code
, as opposed to response_type=token
for the Implicit Grant.
The Authorization Server will now verify the user's identity, and also check whether the application is either implicitly (because it is a trusted application/subscription), or explicitly allowed to access the API on behalf of the user. In case the user has not yet consented to the application accessing the API on behalf of the user, wicked will ask the user to grant access to the application, so that it can access the API on behalf of the user.
If the end user's identity could be verified, the Authorization Server will craft an authorization code which
is passed back to your application with a 302
redirect, giving the authorization code as a
query parameter:
http://your.application.com/oauth2/callback?code=(authorization code)
This authorization code can now be used by your application, which has to call the Token endpoint, passing
the authorization code, and the application's client credentials, to create an access token (and a refresh token).
An example request using curl
would look as follows:
curl -X POST -d 'grant_type=authorization_code&client_id=(your client id)&client_secret=(your client secret)&code=(authorization code)' https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/token
In case of a success, the token endpoint returns a JSON structure which contains an access token and a refresh token:
{ "access_token": "(access token)", "refresh_token": "(refresh token)", "token_type": "bearer", "expires_in": 3600 }
The token expiration depends on the API configuration and can vary between APIs.
Your application can refresh the access token using a specific call to the same /token
end point
as before. Using curl syntax, the call will look like this:
curl -X POST -d 'grant_type=refresh_token&client_id=(your client id)&client_secret=(your client secret)&refresh_token=(refresh token)' https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/token
If successful, the Authorization Server will return a new access token and a new refresh token.
Important: After refreshing the access token using the refresh token, the refresh token which was used for this, is no longer valid. You must then use the new refresh token.
With the returned access token, you may now access the API using the token as a bearer token:
curl -H 'Authorization: Bearer (access token)' https://api.fs-nge-int.haufe.io/(api endpoint)
The actual API endpoint is also displayed on the API's page.
The Authorization Code Grant can also be used for public clients, i.e. clients which are not able to keep a secret. Examples for such applications are Single Page Applications, or very typically, Mobile Apps (native or web based).
The most dangerous threat for such applications is that the Authorization Code is hijacked during the redirect call; if then the client secret can be reverse engineered, it's possible to fully impersonate an application, stealing the logged in user's identity. This is what the PKCE OAuth2 extension mitigates, by a fairly simple exchange of hashed proof keys.
More information on this specification can be found here: https://tools.ietf.org/html/rfc7636.
IMPORTANT: The PKCE extension is highly recommended also for Confidential Clients. It is not only applicable for public clients.
When using a public client, i.e. a client which does not have the "confidential" flag checked in its settings, wicked will not accept
the Authorization Code Grant for this client unless it supplies an additional code_challenge
parameter with the call
to the authorization end point.
To obtain this extra parameter, do as follows:
code_verifier
. The string must only contain digits, characters, .
, -
, _
and ~
(per RFC)code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
Now pass in this as an additional parameter for the authorization call:
https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/authorize?client_id=(your client id)&redirect_uri=(redirect URI of your application)&response_type=code&scope=(space separated list of scopes)&code_challenge=(code challenge)&code_challenge_method=S256
The bold parts of the above URL are the difference to how the call without PKCE looks (for confidential clients). In case the
application associated with the client_id
is not a confidential client, the authorize call will fail unless the code challenge
and code challenge method parameters are passed as well.
Note: Using PKCE is explicitly allowed also for confidential clients.
The call to the token endpoint is also slightly different when using the PKCE extension. For public clients, the
clients secret must not be passed in, but instead the code_verifier
must be part of the payload
for the token endpoint:
curl -X POST -d 'grant_type=authorization_code&client_id=(your client id)&code_verifier=(unhashed code verifier)&code=(authorization code)' https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/token
This applies to public clients; if you are using PKCE with a confidential client (which is explicitly allowed), wicked still
expects the client_secret
to be passed in in addition to the code_verifier
.
In case of a success, the token endpoint returns a JSON structure which contains an access token, but not a refresh token (for public clients):
{ "access_token": "(access token)", "token_type": "bearer", "expires_in": 3600 }
Only when using confidential or native clients, a refresh token is also returned, even if the PKCE extension is used.
Note: Public Clients in the sense of Native/Mobile Applications will be handed a refresh token, just as confidential clients. The below parts only apply for Single Page/Browser Based Applications.
To refresh a token using the Authorization Code Grant using a public client, the same method as with the
implicit grant has to be applied: A silent refresh. In this case, the client needs to call the authorization
end point with a fresh PKCE code_challenge
(as described above), adding also the &prompt=none
parameter to make sure that the call definitely returns, either with a new authorization code, or with
an error.
https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/authorize?client_id=(your client id)&redirect_uri=(redirect URI of your application)&response_type=code&scope=(space separated list of scopes)&code_challenge=(code challenge)&code_challenge_method=S256&prompt=none
By letting this run in a hidden iframe
, the renewal of the access token can be done without the end
user actually noticing.
Public Clients in the sense of Native/Mobile Applications will be handed a refresh token, just as confidential clients.
These clients can use the /token
endpoint directly, just as confidential clients can. The only difference is that native/mobile clients must not present their client_secret
in the call to the /token
endpoint.
curl -X POST -d 'grant_type=refresh_token&client_id=(your client id)&refresh_token=(refresh token)' https://api.fs-nge-int.haufe.io/auth/(auth method id)/api/(api id)/token
If successful, the Authorization Server will return a new access token and a new refresh token.
Important: After refreshing the access token using the refresh token, the refresh token which was used for this, is no longer valid. You must then use the new refresh token.