OAuth 2.0 authorisation request

The authorisation endpoint is where the client obtains the end-user’s authorisation (consent) to access some protected resource (e.g. web API) on their behalf. The vehicle for that is browser redirection:

  1. The client sends the end-user’s browser (typically via a popup window) to the authorisation endpoint of the OAuth 2.0 server. The authorisation request [1] [2] is encoded in the query string of the URI.

  2. At the authorisation endpoint the end-user is typically authenticated and then presented with a consent form or screen. The OAuth 2.0 spec doesn’t prescribe any particular authentication or consent method; the implementation is entirely up to the server and beyond the spec’s scope. The server may for instance employ a username / password credential and a session cookie to authenticate the end-user. The authorisation may also be obtained without any user interaction, e.g. by some business logic. Either way the server should arrive at a decision whether the requesting client is permitted access or not.

  3. The server returns the end-user’s browser back to the client. The response [1] [2] is encoded in the query or fragment string of the URI. Depending on which response_type the client requested, the server will return the following on success:
    • An authorisation code which the client can then exchange for an access token at the token endpoint of the server. This response type requires two steps to obtain a token and is the preferred one for web applications (code flow or grant).
    • The access token directly. This response type is intended for browser-based JavaScript apps and is less secure (implicit flow or grant).

Prerequisites

  1. The client must be pre-registered with the server and have a valid client ID. The client registration may also lock down some of the request parameters, such as the permitted response type, callback URI(s) and available scope values.

  2. The client must be able to maintain secure state between the request and the callback response. The state parameter is intended for that purpose, typically represented by a long random number which is stored in the user session with the client.

Example authorisation request (code flow)

To compose an OAuth 2.0 authorisation request using the code flow:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;

// The authorisation endpoint of the server
URI authzEndpoint = new URI("https://c2id.com/authz");

// The client identifier provisioned by the server
ClientID clientID = new Client("123");

// The requested scope values for the token
Scope scope = new Scope("read", "write");

// The client callback URI, typically pre-registered with the server
URI callback = new URI("https://client.com/callback");

// Generate random state string for pairing the response to the request
State state = new State();

// Build the request
AuthorizationRequest request = new AuthorizationRequest.Builder(
    new ResponseType(ResponseType.Value.CODE), clientID)
    .scope(scope)
    .state(state)
    .redirectionURI(callback)
    .endpointURI(authzEndpoint)
    .build();

// Use this URI to send the end-user's browser to the server
URI requestURI = request.toURI();

At the client callback endpoint:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;

// Parse the authorisation response from the callback URI
AuthorizationResponse response = AuthorizationResponse.parse(new URI("..."));

if (! response.indicatesSuccess()) {

    // The request was denied or some error may have occurred
}

AuthorizationSuccessResponse successResponse = (AuthorizationSuccessResponse)response;

// The returned state parameter must match the one send with the request
if (! state.equals(successResponse.getState()) {
    // Unexpected or tampered response, stop!!!
}

// Retrieve the authorisation code, to be used later to exchange the code for
// an access token at the token endpoint of the server
AuthorizationCode code = successResponse.getAuthorizationCode();

Example authorisation request (implicit flow)

To compose an OAuth 2.0 authorisation request using the implicit flow:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;
import com.nimbusds.oauth2.sdk.token.*;

// The authorisation endpoint of the server
URI authzEndpoint = new URI("https://c2id.com/authz");

// The client identifier provisioned by the server
ClientID clientID = new Client("123");

// The requested scope values for the token
Scope scope = new Scope("read", "write");

// The client callback URI, typically pre-registered with the server
URI callback = new URI("https://client.com/callback");

// Generate random state string for pairing the response to the request
State state = new State();

// Build the request
AuthorizationRequest request = new AuthorizationRequest.Builder(
    new ResponseType(ResponseType.Value.TOKEN), clientID)
    .scope(scope)
    .state(state)
    .redirectionURI(callback)
    .endpointURI(authzEndpoint)
    .build();

// Use this URI to send the end-user's browser to the server
URI requestURI = request.toURI();

At the client callback endpoint:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;

// Parse the authorisation response from the callback URI
AuthorizationResponse response = AuthorizationResponse.parse(new URI("..."));

if (! response.indicatesSuccess()) {
    // The request was denied or some error may have occurred
}

AuthorizationSuccessResponse successResponse = (AuthorizationSuccessResponse)response;

// The returned state parameter must match the one send with the request
if (! state.equals(successResponse.getState()) {
    // Unexpected or tampered response, stop!!!
}

// Retrieve the token, which can now be used to make requests to the
// protected resource (web API)
AccessToken token = successResponse.getAccessToken();

Custom parameters

Version 5.8 introduces support for adding custom (non-standard) parameters to the authorisation request, for example experimental parameters that have not yet been standardised.

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;

// Build the request
AuthorizationRequest request = new AuthorizationRequest.Builder(
    new ResponseType(ResponseType.Value.CODE), new ClientID("123"))
    .scope(new Scope("read", "write")
    .state(new State("xyz...")
    .redirectionURI(URI.create("https://example.com/callback")
    .customParameter("resource", "https://example.com/resource")
    .endpointURI("https://c2id.com/authorize")
    .build();

// Getting a custom parameter
String resource = request.getCustomParameter("resource");

// Getting a map of all custom parameters
Map<String,String> customParams = request.getCustomParameters();

Server-side authorisation request processing

Example:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.id.*;

// Get the query string from the request URI
String query = requestURI.getQuery();

// Parse the authorisation request
AuthorizationRequest request = AuthorizationRequest.parse(query);

// Extract and validate the request parameters...

// Required to look up the client in the server's database
ClientID clientID = req.getClientID();

// The client callback URL, must be registered in the server's database
URL callback = req.getRedirectionURI();

// The state, must be echoed back with the response
State state = req.getState();

// The requested scope
Scope scope = req.getScope();

// Authenticate the end-user, gather consent...

// Generate the response...
AuthorizationResponse response;

if (success) {

    if (request.getResponseType().equals(new ResponseType(ResponseType.Value.CODE)) {

        // Generate authorisation code and save it...
        AuthorizationCode code = new AuthorizationCode();
        response = AuthenticationSuccessResponse(callback, code, state);
    } else if (request.getResponseType().equals(new ResponseType(ResponseType.Value.TOKEN)) {

        // Generate access token...
        AccessToken code = new BearerAccessToken(...);
        response = AuthenticationSuccessResponse(callback, code, state);
    }
} else if (authorizationDenied) {

    // Signal access denied
    response = new AuthorizationErrorResponse(callback,
        OAuth2Error.ACCESS_DENIED,
        request.getResponseType(),
        state);
} else {
    // Handle other errors...
}

// Output the response depending on your web server framework
// ...

References