In order to be able to access ONE Reporting service, a client should add Authorization: Bearer TOKEN header to each request. The client should be provisioned with both client_id and client_secret for QA/DEV and PROD environments. After these values are obtained, client_id should be registered within ONE Reporting system.

Note: token url for stage (UAT) https://id-uat.b2b.yahooinc.com/identity/oauth2/access_token

Note: token url for PROD https://id.b2b.yahooinc.com/identity/oauth2/access_token

Note: client_secret is always private and should never be shared.

    Below is the code sample for OAuth 2.0 access token generation for ONE Reporting.

    
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)