Obtaining an Access Token

How to write a client using Oauth2 Signed Assertions (JWT profile) authentication/authorization

1. Request the token from the Authorization Server

  • An HTTP POST request to the endpoint /oauth/v2/token in accordance with RFC 7521 section 4.2 and the specifications referenced below.
  • The body of the request should include the following parameters
    • grant_type=client_credentials as specified in RFC 6749 section 4.4.2
    • client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer as specified in RFC 7523 section 2.2 and section 8.1
    • client_assertion=eyJhbGciOiJSUzI1NiIsI.eyJpc3Mi.cC4hiUPo which is the signed JWT as described in RFC 7519
    • code=value where value is a random string generated by the API client for CSRF protection.
  • The body should be encoded using the "application/x-www-form-urlencoded" encoding algorithm as specified in RFC 6749 appendix B.
  • An example request is shown in RFC 7523 section 2.2.
  • The value of the client_assertion parameter is created by creating a JWT in accordance with: RFC 7523 section 2.3
  • The following claims must be in the JWT
    • iss: The issuer of the JWT. We don't currently do anything with the issuer value. However, it must be present.
    • sub: The sub value must be the client_id. The client_id should match an ApiUser.lookup_code.
    • aud: The audience value must match the hostname of the Authorization Server.
    • exp: The expiration time of the JWT. The time must not be in the past.
    • jti: See specification for details. A unique identifier for this token request. A new jti should be allocated after the length of time for which the JWT would be considered valid based on the applicable "exp" value.
    • scopes: is the requested scope(s), a space separated list of valid scopes defined in the Authentication Profile section below as specified in RFC 6749 section 3.3 and RFC 7521 section 4.1
  • The JWT must be signed.

📘

API User Access

This guide assumes you have been provided an API user in the PlanSource system. If you have not yet received your API user credentials, please reach out to your PlanSource point of contact for assistance.

2. Use the access token to access the Resource Server
The client makes a request to the endpoint using the token received from the Authorization Server as a Bearer token in the Authorization header (RFC 6750 section 2.1). We do not support the Form-Encoded Body Parameter or URI Query Parameter methods of using the Bearer token for utility/security reasons.

Authentication/Authorization errors

TypeErrorDescription
Authorization Server / Resource Serverinvalid_requestSee RFC 6749 section 5.2 and See RFC 6750 section 3.1
Authorization Serverinvalid_clientSee RFC 6749 section 5.2
Authorization Serverinvalid_grantSee RFC 6749 section 5.2
Authorization Serverunauthorized_clientSee RFC 6749 section 5.2
Authorization Serverunsupported_grant_typeSee RFC 6749 section 5.2
Authorization Serverinvalid_scopeSee RFC 6749 section 5.2
Authorization Serverinvalid_scopeSee RFC 6749 section 5.2
Resource Serverinvalid_tokenSee RFC 6750 section 3.1
Resource Serverinsufficient_scopeSee RFC 6750 section 3.1

Authentication Profiles

Oauth Signed Assertions

Attribute Definitions

FieldDescription
User Key
(client_secret):
The client_secret. Used directly in authentication/authorization decisions. Required. Provided by PlanSource
Lookup Code
(client_id):
The client_id. A unique public identifier used to look up the API user. Required. Provided by PlanSource
Authentication Types:Currently hard coded to "all". We currently support "client_secret_jwt" (RFC 7523). Soon will also have "client_secret_saml" (RFC 7522)
Scopes:admin_api_v2
self_service_api_v1
all

Sample Assertion

786 873

This is a pre-request script in Postman that is written in JavaScript. This sample stores the client secret, client lookup code, host URL, and the variables for the JWT. The JWT is then built and sent as the client_assertion to the access token endpoint.

var audience = "https://partner-dev-api.plansource.com/";
var secret = "PlanSourceProvidedClientSecret/UserKey";

var header = {
  "alg": "HS256",
  "typ": "JWT"
};

var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = CryptoJS.enc.Base64.stringify(stringifiedHeader);

var data = {
  "iss":"dont care",
  "sub": "PlanSourceProvidedClientLookupCode",
  "aud": audience,
  "scopes": "admin_api_v2",
  "exp": (new Date() / 1000) + 3,
  "logged_in_user": "PlanSourceProvidedClientAdministratorUserName",
};

var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = CryptoJS.enc.Base64.stringify(stringifiedData);
var token = encodedHeader + "." + encodedData;

var signature = CryptoJS.HmacSHA256(token, secret);
signature = CryptoJS.enc.Base64.stringify(signature);

var signedToken = token + "." + signature;
postman.setEnvironmentVariable("signedToken", signedToken);