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.
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.
Configure WSO2 APIManager to pass JWT token
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;
<RemoveOAuthHeadersFromOutMessage>false</RemoveOAuthHeadersFromOutMessage>
With current JWT token implementation of APIManager,following details will be pass to backend endpoint.
- Subscriber Name
- Application Name
- Tier
- End-User Name
- API context
- Version
- Key Type [Production/Sandbox]
- User Type[Application Token/User Token]
Configure WSO2 APIManager to pass JWT token
- Enable JWT token generation by uncommenting below configuration and set its value as true from api-manager.xml.
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"}
"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=="}
{"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"}
"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.
If you want to pass an OAuth access token to back-end,modify the below configuration in api-manager.xml.
<RemoveOAuthHeadersFromOutMessage>false</RemoveOAuthHeadersFromOutMessage>
Hi Lalaji,
ReplyDeleteThank 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
Hello Lalaji - I follow the same steps, but I don't see X-JWT-Assertion is getting created, please help!
ReplyDeleteIs this possible to decode X-JWT-Assertion using OpenSAML library? If yes, could you please guide here ?
ReplyDeleteCould you please share code which uses Restful Controller to receive the X-JWT-assertion from WSO2 APIM ?
ReplyDeleteCan you please provide details on how to do the signature validation? Thanks Reshma
ReplyDeleteI 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.
ReplyDeleteNo 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