Create a Token for Reporting API

When accessing ONE Reporting, clients must always include an Authorization: Bearer Token header in each request. Provision the client with both client_id and client_secret for both the QA/DEV and PROD environments. Once these values are obtained, the client_id must be registered within the O2 system.

  • Token URL for stage (UAT) - https://id-uat.b2b.oath.com/identity/oauth2/access_token
  • Token URL for PROD - https://id.b2b.oath.com/identity/oauth2/access_token
  • Client_secret is always private and should never be shared

 

package oauth2;

 

import java.util

import com.fasterxml.jackson.databind.ObjectMapper

import com.fasterxml.jackson.module.scala.DefaultScalaModule

import org.jose4j.jws.{AlgorithmIdentifiers, JsonWebSignature}

import org.jose4j.jwt.{JwtClaims, NumericDate}

import org.jose4j.keys.HmacKey

import org.springframework.http.converter.FormHttpMessageConverter

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

import org.springframework.http.{HttpEntity, HttpHeaders, HttpMethod, MediaType}

import org.springframework.util.{LinkedMultiValueMap, MultiValueMap}

import org.springframework.web.client.RestTemplate

import scala.collection.JavaConverters._

/*** Is used to retrieve OAuth 2.0 access token in Identity B2B platform*/ object AccessTokenFetchService {

/** Fetch the token by the provided credentials

* @param credentials see: [[Credentials]]

* @return OAuth 2.0 access token along, see: [[AccessToken]]

*/

def fetch(credentials: Credentials): AccessToken = {

val payload = constructPayload(credentials)

val httpEntity = new HttpEntity[MultiValueMap[String, String]](payload, prepareHttpHeaders)

// token request is a POST HTTP request on the Identity B2B platform endpoint url

// with the payload consisting of url-encoded query params restTemplate.exchange(credentials.tokenUrl, HttpMethod.POST, httpEntity, classOf[AccessToken]).getBody

}

// payload key-value pairs private def constructPayload(credentials: Credentials): MultiValueMap[String, String] = {

val map = Map(

"client_assertion_type" -> credentials.clientAssertionType,

"grant_type" -> credentials.grantType,

"scope" -> credentials.scope,

"realm" -> credentials.realm,

"client_assertion" -> generateJsonWebToken(credentials)

).map { case (name, value) => name -> Seq(value).asJava }.asJava

new LinkedMultiValueMap[String, String](map)

}

 

// JWT token generation by the provided credentials

private def generateJsonWebToken(credentials: Credentials): String = {

val claims = new JwtClaims

claims.setIssuedAt(NumericDate.now)

claims.setExpirationTimeMinutesInTheFuture(5)

claims.setSubject(credentials.clientId)

claims.setIssuer(credentials.clientId)

claims.setAudience(getAudience(credentials.tokenUrl, credentials.realm))

claims.setGeneratedJwtId()

val key = new HmacKey(credentials.clientSecret.getBytes("UTF-8"))

val jws = new JsonWebSignature

jws.setPayload(claims.toJson)

jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256)

jws.setKey(key)

jws.setDoKeyValidation(false)

jws.getCompactSerialization

}

private def getAudience(url: String, realm: String) = String.format("%s?realm=%s", url, realm)

// HTTP headers expected by Identity B2B platform

private def prepareHttpHeaders = {

val headers = new HttpHeaders

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED)

headers.setAccept(Seq(MediaType.APPLICATION_JSON).asJava)

headers

}

 

// spring-web rest template to make http calls

private lazy val restTemplate = {

val restTemplate = new RestTemplate

val mapper = new ObjectMapper mapper.registerModule(DefaultScalaModule)

val jacksonConverter = new MappingJackson2HttpMessageConverter(mapper)

restTemplate.setMessageConverters(util.Arrays.asList(jacksonConverter, new FormHttpMessageConverter))

restTemplate

}

}

 

 

package oauth2;

 

/**

* The credentials needed for OAuth 2.0 token

* generation in Identity B2B platform

*/

trait Credentials {

def tokenUrl: String

def scope: String

def clientId: String

def clientSecret: String

def realm: String

def grantType: String

def clientAssertionType: String

}

 

 

package oauth2;

 

/**

* Container for the credentials to generate One Reporting OAuth 2.0 token

* @param tokenUrl identity B2B platform token generation endpoint url

* @param clientId the provided by One Central client id

* @param clientSecret the provided by One Central client secret

* @param scope OAuth 2.0 scope, defaults to "one"

* @param realm OAuth 2.0 realm, defaults to "aolcorporate/aolexternals"

* @param grantType OAuth 2.0 grant type, defaults to "client_credentials"

* @param clientAssertionType OAuth 2.0 assertion type with the default value

*/

case class ReportingCredentials(tokenUrl: String,

clientId: String,

clientSecret: String,

scope: String = "one",

realm: String = "aolcorporate/aolexternals",

grantType: String = "client_credentials",

clientAssertionType: String = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")

extends Credentials

 

 

package oauth2;

 

import com.fasterxml.jackson.annotation.JsonProperty

/**

* Identity B2B platform successful response on token generation

* @param token the generated access token

* @param scope OAuth 2.0 scope of the generated access token

* @param tokenType OAuth 2.0 token type (Bearer)

* @param expiresIn expiration time in seconds

*/

case class AccessToken(@JsonProperty("access_token") token: String,

@JsonProperty("scope") scope: String,

@JsonProperty("token_type") tokenType: String,

@JsonProperty("expires_in") expiresIn: Int)