OAuth 2.0 token request

The token endpoint of an OAuth 2.0 authorisation server is where a client obtains its access token, in exchange for a valid credential, called grant.

The core OAuth 2.0 spec (RFC 6749) defines four types of grants for use at the token endpoint. An authorisation server may support one or more of them.

  1. Authorisation code -- this is an opaque credential obtained at the authorisation endpoint, encapsulating the end-user's consent given to the client. The code grant is the most commonly used one, and it offers optimal security.

  2. Resource owner password credentials -- the client collects the end-user's username and password and submits them to the OAuth 2.0 server. Don't use this grant, unless you absolutely can't have the code or implicit grant. The whole point of OAuth is to provide a single trusted point for users to submit their credentials, so the various of security pitfalls of disclosing user credentials to client apps are altogether avoided.

  3. Client credentials -- intended for cases when the client is acting on its own behalf (the client is the resource owner). The grant is the client's registered credentials (client_id and usually a client_secret).

  4. Refresh token -- opaque credential issued by the authorisation server, allows the client to obtain a new access token when the current access token becomes invalid or expires.

The implicit grant (or flow) is the only one which doesn't require the client to interact with the token endpoint of the OAuth 2.0 server. Instead, client receives the access token directly from the authorisation endpoint.

The grant is an open concept, and since the publication of the code OAuth 2.0 spec a number of other grant types were developed. One such grant enables the exchange of SAML assertions for access tokens. Another, to handle input constrained devices.

Prerequisites

  1. The client must be registered with the OAuth 2.0 server and have a valid client ID. The client registration may lock down some of the token request parameters, such as the permitted grant types and token scope.

  2. The client must have obtained a valid grant, e.g. an authorisation code.

Example token request with a code grant

To make a token request with a code grant which was previously obtained from the authorisation endpoint.

For a confidential client (with a client_id and client_secret):

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

// Construct the code grant from the code obtained from the authz endpoint
// and the original callback URI used at the authz endpoint
AuthorizationCode code = new AuthorizationCode("xyz...");
URI callback = new URI("https://client.com/callback");
AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callback);

// The credentials to authenticate the client at the token endpoint
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("secret");
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);

// The token endpoint
URI tokenEndpoint = new URI("https://c2id.com/token");

// Make the token request
TokenRequest request = new TokenRequest(tokenEndpoint, clientAuth, codeGrant);

TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send());

if (! response.indicatesSuccess()) {
    // We got an error response...
    TokenErrorResponse errorResponse = response.toErrorResponse();
}

AccessTokenResponse successResponse = response.toSuccessResponse();

// Get the access token, the server may also return a refresh token
AccessToken accessToken = successResponse.getTokens().getAccessToken();
RefreshToken refreshToken = successResponse.getTokens().getRefreshToken();

For a public client (with client_id only):

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

// Construct the code grant from the code obtained from the authz endpoint
// and the original callback URI used at the authz endpoint
AuthorizationCode code = new AuthorizationCode("xyz...");
URI callback = new URI("https://client.com/callback");
AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callback);

// The client ID to identify the client at the token endpoint
ClientID clientID = new ClientID("123");

// The token endpoint
URI tokenEndpoint = new URI("https://c2id.com/token");

// Make the token request
TokenRequest request = new TokenRequest(tokenEndpoint, clientID, codeGrant);

TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send());

if (! response.indicatesSuccess()) {
    // We got an error response...
    TokenErrorResponse errorResponse = response.toErrorResponse();
}

AccessTokenResponse successResponse = response.toSuccessResponse();

// Get the access token, the server may also return a refresh token
AccessToken accessToken = successResponse.getTokens().getAccessToken();
RefreshToken refreshToken = successResponse.getTokens().getRefreshToken();

Example token request with a password grant

To make a token request with the end-user's name and password credentials (password grant):

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

// Construct the password grant from the username and password
String username = "[email protected]";
Secret password = new Secret("password");
AuthorizationGrant passwordGrant = new ResourceOwnerPasswordCredentialsGrant(username, password);

// The credentials to authenticate the client at the token endpoint
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("secret");
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);

// The request scope for the token (may be optional)
Scope scope = new Scope("read", "write");

// The token endpoint
URI tokenEndpoint = new URI("https://c2id.com/token");

// Make the token request
TokenRequest request = new TokenRequest(tokenEndpoint, clientAuth, passwordGrant, scope);

TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send());

if (! response.indicatesSuccess()) {
    // We got an error response...
    TokenErrorResponse errorResponse = response.toErrorResponse();
}

AccessTokenResponse successResponse = response.toSuccessResponse();

// Get the access token, the server may also return a refresh token
AccessToken accessToken = successResponse.getTokens().getAccessToken();
RefreshToken refreshToken = successResponse.getTokens().getRefreshToken();

Example token request with a client credentials grant

To make a token request with the client acting on its own behalf:

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

// Construct the client credentials grant
AuthorizationGrant clientGrant = new ClientCredentialsGrant();

// The credentials to authenticate the client at the token endpoint
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("secret");
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);

// The request scope for the token (may be optional)
Scope scope = new Scope("read", "write");

// The token endpoint
URI tokenEndpoint = new URI("https://c2id.com/token");

// Make the token request
TokenRequest request = new TokenRequest(tokenEndpoint, clientAuth, clientGrant, scope);

TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send());

if (! response.indicatesSuccess()) {
    // We got an error response...
    TokenErrorResponse errorResponse = response.toErrorResponse();
}

AccessTokenResponse successResponse = response.toSuccessResponse();

// Get the access token
AccessToken accessToken = successResponse.getTokens().getAccessToken();

Example request with a refresh token

To obtain a new access token if you have a refresh token:

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

// Construct the grant from the saved refresh token
RefreshToken refreshToken = new RefreshToken("xyz...");
AuthorizationGrant refreshTokenGrant = new RefreshTokenGrant(refreshToken);

// The credentials to authenticate the client at the token endpoint
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("secret");
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);

// The token endpoint
URI tokenEndpoint = new URI("https://c2id.com/token");

// Make the token request
TokenRequest request = new TokenRequest(tokenEndpoint, clientAuth, refreshTokenGrant);

TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send());

if (! response.indicatesSuccess()) {
    // We got an error response...
    TokenErrorResponse errorResponse = response.toErrorResponse();
}

AccessTokenResponse successResponse = response.toSuccessResponse();

// Get the access token, the refresh token may be updated
AccessToken accessToken = successResponse.getTokens().getAccessToken();
RefreshToken refreshToken = successResponse.getTokens().getRefreshToken();

Bearer assertion grants

The Nimbus OAuth 2.0 SDK also supports the SAML 2.0 bearer and the JWT bearer grants.

Check the JavaDocs for the SAML2BearerGrant and the JWTBearerGrant classes for how to construct and parse them.

References