Saturday, June 29, 2013

Passing end-user details from client to real backend endpoint via JWT token

In real-world business system,WSO2 API Manager useful on exposing company APIs, in a secured and controlled manner with the features provided by APIManager as;
  • OAuth support [To secure API invocations]
  • Throttling support [To control API invocations]
  • Monitoring support [To track API usage]
More technically what happening is when a user sends a particular API request,it will goes to WSO2 APIManager node and from there,the request will route to the real implemented back-end endpoint of the particular API and get back the response and returned it to the API invoked user. There can be a use-case,that this back-end endpoint may expect the details of API invoked user as to pass those details to some internal company usage  as;
  • Additional authentication/authorization
  • Track usage data from an internal system.
So how to support above requirement from WSO2 AM.
There comes the use of JSON Web Token[JWT] implementation done inside WSO2 AM. JWT is a means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JavaScript Object Notation (JSON) object that is used as the payload of a JSON Web Signature (JWS) structure or as the plain-text of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or MACed and/or encrypted.For get more information on JWT tokens ,please refer this link.
With current JWT token implementation of APIManager,following details will be pass to backend endpoint.

  1. Subscriber Name
  2. Application Name
  3. Tier
  4. End-User Name
  5. API context
  6. Version
  7. Key Type [Production/Sandbox]
  8. User Type[Application Token/User Token]
Below blog content will guide you on how to enable JWT token passing support from APIManager.

Configure WSO2 APIManager to pass JWT token

  1. Enable JWT token generation by uncommenting below configuration and set its value as true from api-manager.xml.
       <EnableTokenGeneration>true</EnableTokenGeneration>

    2. Start the AM server,create,publish API and subscribe it from the APIStore.


    3. Invoke the API and capture the outgoing message from the API Manager.Here its required to 

      monitor transport level header values as JWT token will be pass to backend as a transport header.

      To capture the outgoing message,you can use;

  • By Tcpmon tool in-between APIManager node and backend endpoint.For more info,refer the blog.
  • By enabling  wire logs of APIManager -By updating below configurations into log4j.properties file which can be found from {AM_Home}/repository/conf.If you follow this,you need to restart AM node.
        Uncomment  log4j.category.org.apache.synapse.transport.nhttp.wire=DEBUG
        Update log4j.category.org.apache.synapse.transport=INFO as  
        log4j.category.org.apache.synapse.transport=DEBUG

With capturing APIManager outputting message from one of either above option,you'll see a HTTP header  name as  "X-JWT-Assertion" has append to transport headers.Note the JWT-Assertion header value will contains base64 encoded value.If you capture the outgoing message of    APIM with wirelogs,when you invoke an API,you'll see below logs will be output in APIM with JWT-Assertion.

TID: [0] [AM] [2013-06-29 09:05:05,548] DEBUG {org.apache.synapse.transport.http.headers} -  http-outgoing-1>>X-JWT-Assertion: eyJ0eXAiOiJKV1QiLCJhbGciOiJTSEEyNTZ3aXRoUlNBIiwieDV0IjoiTm1KbU9HVXhNelpsWWpNMlpEUmhOVFpsWVRBMVl6ZGhaVFJpT1dFME5XSTJNMkptT1RjMVpBPT0ifQ==.eyJpc3MiOiJ3c28yLm9yZy9wcm9kdWN0cy9hbSIsImV4cCI6MTM3MjUyMjgwNTE3NywiaHR0cDovL3dzbzIub3JnL2NsYWltcy9zdWJzY3JpYmVyIjoibGFsYWppIiwiaHR0cDovL3dzbzIub3JnL2NsYWltcy9hcHBsaWNhdGlvbmlkIjoiMSIsImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvYXBwbGljYXRpb25uYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaHR0cDovL3dzbzIub3JnL2NsYWltcy9hcHBsaWNhdGlvbnRpZXIiOiJVbmxpbWl0ZWQiLCJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2FwaWNvbnRleHQiOiIvYXBpMSIsImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvdmVyc2lvbiI6IjEuMi4zIiwiaHR0cDovL3dzbzIub3JnL2NsYWltcy90aWVyIjoiVW5saW1pdGVkIiwiaHR0cDovL3dzbzIub3JnL2NsYWltcy9rZXl0eXBlIjoiUFJPRFVDVElPTiIsImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvdXNlcnR5cGUiOiJBUFBMSUNBVElPTiIsImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvZW5kdXNlciI6ImxhbGFqaSIsImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvZW5kdXNlclRlbmFudElkIjoiLTEyMzQifQ==.YtVaDtRYtfUkVDvwe9V8oqsXK8OkB4HUhsQS2z3ngWRNjAktSKWlH+Is9T5EQnsg8hrsJQ4nKDdwDWHAUIFxIsb7bX/Y1O+WSLMLZYQ11WVzFaw50BJuqPbL9ZOfux1iRnm4ZbxClVSan72g/w8a05UnCvsGyIh5oCP4RUsAhXo= {org.apache.synapse.transport.http.headers}

To get the end user details,above base64 encoded string need to decode back.NOTE -Above encoded string contains three seperate encoded values.Those three are seperated from '.' [dot] sign. I have highlighted those three strings with different colors in above. You need to decode first two encoded strings to retrieve whole token structure.To decode,you can use www.base64decode.org link.
Once you decode,above first encoded string [green colored] ,you'll get an output as;

{"typ":"JWT","alg":"SHA256withRSA","x5t":"NmJmOGUxMzZlYjM2ZDRhNTZlYTA1YzdhZTRiOWE0NWI2M2JmOTc1ZA=="}
Above will output the token type as JWT and the algorithm used to encode the value as SHA256withRSA.



Then you can decode above second encoded string[red colored],you'll get end-user details as below.

{"iss":"wso2.org/products/am","exp":1372522805177,
"http://wso2.org/claims/subscriber":"lalaji",
"http://wso2.org/claims/applicationid":"1",
 "http://wso2.org/claims/applicationname":"DefaultApplication",
 "http://wso2.org/claims/applicationtier":"Unlimited",
 "http://wso2.org/claims/apicontext":"/api1",
 "http://wso2.org/claims/version":"1.2.3",
"http://wso2.org/claims/tier":"Unlimited",
"http://wso2.org/claims/keytype":"PRODUCTION",
"http://wso2.org/claims/usertype":"APPLICATION",
 "http://wso2.org/claims/enduser":"lalaji",
"http://wso2.org/claims/enduserTenantId":"-1234"}

Such that the overall Token Structure would be like below format;
{"typ":"JWT","alg":"SHA256withRSA","x5t":"NmJmOGUxMzZlYjM2ZDRhNTZlYTA1YzdhZTRiOWE0NWI2M2JmOTc1ZA=="}


{"iss":"wso2.org/products/am","exp":1372522805177,
"http://wso2.org/claims/subscriber":"lalaji",
"http://wso2.org/claims/applicationid":"1",
 "http://wso2.org/claims/applicationname":"DefaultApplication",
 "http://wso2.org/claims/applicationtier":"Unlimited",
 "http://wso2.org/claims/apicontext":"/api1",
 "http://wso2.org/claims/version":"1.2.3",
"http://wso2.org/claims/tier":"Unlimited",
"http://wso2.org/claims/keytype":"PRODUCTION",
"http://wso2.org/claims/usertype":"APPLICATION",
 "http://wso2.org/claims/enduser":"lalaji",
"http://wso2.org/claims/enduserTenantId":"-1234"}


How to pass Access Token used to invoke API to backend


With above JWT token approach,it'll pass the end user details and the invoked API data.But it will not pass the access token to backend. In WSO2 APIManager default behaviour,once an API request comes with an access token include in the Authorization header,it'll first processed the API Key validation handler and drop that access token contained Authorization header from message,without passing it to back-end endpoint.
If you want to pass an OAuth access token to back-end,modify the below configuration in api-manager.xml.

<RemoveOAuthHeadersFromOutMessage>false</RemoveOAuthHeadersFromOutMessage>


No comments:

Post a Comment