Skip to main content

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>


Comments

  1. Hi Lalaji,

    Thank you for nice post. However it's not finding much useful because you've not given any steps/information how to publish the project, because of the lack of steps we're unable to execute this example to get JWT assertion from WSO2 APIM. Please help us?

    Thank you, Geeta

    ReplyDelete
  2. Hello Lalaji - I follow the same steps, but I don't see X-JWT-Assertion is getting created, please help!

    ReplyDelete
  3. Is this possible to decode X-JWT-Assertion using OpenSAML library? If yes, could you please guide here ?

    ReplyDelete
  4. Could you please share code which uses Restful Controller to receive the X-JWT-assertion from WSO2 APIM ?

    ReplyDelete
  5. Can you please provide details on how to do the signature validation? Thanks Reshma

    ReplyDelete
  6. I need to pass the some request parameter in JWT(WSO2). Do you have any idea about it how to do so? I have created my own custom JWT generator.

    ReplyDelete
    Replies
    1. No need to create custom JWT. Just map claim in claim configuration of your service provider. https://docs.wso2.com/display/IS500/Adding+New+Claim+Mapping

      Delete

Post a Comment

Popular posts from this blog

Convert an InputStream to XML

For that we can use DocumentBuilder class in java. By using the method parse(InputStream) ; A new DOM Document object will return. InputStream input; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); Document dc= parser.parse(input); In the above code segment,by using the created Document object,the corresponding XML file for the inputStream can be accessed. References: http://www.w3schools.com/dom/dom_intro.asp http:// download.oracle.com/javase/1.4.2/docs/api/javax/xml/parsers/DocumentBuilder.html

Concat two xml values with XSLT

The use-case described in this blog-post,is there's an WSO2 ESB node setup to proxy an incoming message to a particular back-end endpoint.  Before delivering the message to the back-end endpoint,from the ESB node itself,this incoming message need to processed and change its inside xml payload format. For eg: Below is the incoming message <?xml version="1.0" encoding="UTF-8"?> <CinemaHall name="liberty"> <OwnerData> <Name>John Smith</Name> <openedDate>12/12/80</openedDate> <quality>good</quality> </OwnerData> <CinemaHallData> <rows>100</rows> <seats> <seat>50</seat> <seat>60</seat> </seats> </CinemaHallData> </CinemaHall> This message need to be changed as  below; <?xml version="1.0" encoding="UTF-8"?> <CinemaHall name="liberty"...