Invoking APIs using a Web App with OAuth2 and use of JWT – WSO2 API Manager
In this post I am to share my experience and understandings using WSO2 API Manager(API-M) for a very common and useful scenario in the industry.
In brief following is the flow.
An API is exposed for app developers to be used under the control of API Manager (which adds access control for the API). Then app developers make their apps consuming those APIs. After development and testing is completed they make it available for end users at App store. The end users can then get registered in the store and use the apps with own credentials. The app will provide the desired services calling the APIs it has subscribed to.
The above scenario is well demonstrated in WSO2 API-M with the pizza shack example explained in the documentation at [1].
For clarity I will be including the steps in brief. For detailed steps we can refer documentation at [1].
API Developer Role
- We deploy the back-end services related to ‘pizza ordering’ in WSO2-Application server or any other desired application server. (Download the code from API-M samples svn, build using Maven3 and deploy it in WSO2 AS. If we check the WADL, we can check the resources it exposes. Note the endpoint URL.)
- Then we publishes these services as APIs in WSO2 API-M Publisher, so that they will be available in API-M Store (Login to API-M Publisher, in default pack https://localhost:9443/publisher and publish the APIs as guided in the sample doc. We should make sure the production endpoint URL matches with what we observed in the first step).
App Developer Role
- Now here comes an App developer who wish to develop an App to order Pizza. He/she can register this App in store and get subscribed to these APIs that are required for development of application. So this APP developer will be consuming the services exposed by the APIs published by the previous developer. The code for the pizza ordering sample web app can be downloaded from svn as well.
- At subscription he/she gets consumer secret and consumer key which are then used to request OAuth tokens to access the APIs (In this example we use user name and password which is required in grant type ‘password’. There are several other possible grant types as well, if we don’t want to send password).
Get the consumer key and secret from ‘My Subscriptions’.
- Developer embeds the consumer key and consumer secret into the Pizza ordering application (In most of the cases in web.xml).
<context-param> <param-name>consumerKey</param-name> <param-value>FyfSK4RNHqGETmnNkaI87hIoNFQa</param-value> </context-param> <context-param> <param-name>consumerSecret</param-name> <param-value>1NFr7jb8JBA3IFa6gkjoN_PoYAca</param-value> </context-param>
At this point we can check how the token works with a simple curl command as follows. Provide the access token taken from above UI.
curl -k -H "Authorization: Bearer <access_token>" https://localhost:8245/pizzashack/menu/1.0.0
which will return the menu details for pizza orering as follows,
[{"price":"13.99","icon":"/images/6.png","description":"Grilled white chicken, hickory-smoked bacon and fresh sliced onions in barbeque sauce","name":"BBQ Chicken Bacon"},{"price":"24.99","icon":"......................:"/images/5.png","description":"Rich and creamy blend of spinach and garlic Parmesan with Alfredo sauce","name":"Spinach Alfredo"},{"price":"15.99","icon":"/images/4.png","description":"Six cheese blend of mozzarella, Parmesan, Romano, Asiago and Fontina","name":"Tuscan Six Cheese"}]
Since we have already seen the access token we can use it here. But when an end user comes and tries to order pizzas he/she is not seen these. Also this token is related with USER_TYPE: APPLICATION which has more privileges than an end user, so we can’t anyway let the user use it. So what is happening underneath is generating a separate token for end users, using the embedded consumer key/secret and end user entered credentials(if password grant type is used) which will be related with USER_TYPE: APPLICATION_USER.
End User
So here comes the end user who get registered in the App Store.
Then end users can use the application to order pizzas online, entering their credentials in the application at http://localhost/pizzashack.
The API-M sitting in the middle act as the Authorization server in the scenario, managing the usage of the exposed APIs.
So where does the JWT assertion comes into play?
JWT assertion is a format used to send the details of the end user who invoked the API. Just as a SAML assertion would carry user claims JWT also carries user claims in JSON notation. We can find more details on this at [2]. This is used to pass those details to the back-end service which might require them for monitoring or some other purpose. The default JWT token will be as follows.
{ "iss":"wso2.org/products/am", "exp":1391029971429, "http://wso2.org/claims/subscriber":"admin", "http://wso2.org/claims/applicationid":"1", "http://wso2.org/claims/applicationname":"DefaultApplication", "http://wso2.org/claims/applicationtier":"Unlimited", "http://wso2.org/claims/apicontext":"/pizzashack/menu", "http://wso2.org/claims/version":"1.0.0", "http://wso2.org/claims/tier":"Bronze", "http://wso2.org/claims/keytype":"PRODUCTION", "http://wso2.org/claims/usertype":"APPLICATION", "http://wso2.org/claims/enduser":"admin", "http://wso2.org/claims/enduserTenantId":"-1234" }
Cheers!
Resources:
- http://docs.wso2.org/display/AM150/Invoking+APIs+using+a+Web+App+Deployed+in+WSO2+AS
- http://lalajisureshika.blogspot.com/2013/06/passing-end-user-details-from-client-to.html
- http://asanka.abeysinghe.org/2014/01/oauth-for-application-developer-and.html
very informative and detailed explanation.. keep posting …
Thanks tech02. It’s encouraging.
Hi Pushpalanka,
I am newbie to the WSO2 API Manager. I would like to learn this product, in this product I would like to create Proxy for the RESTFul web services (Spring MVC REST). How we can do that? Could you please share simple example with steps ?
I search a lot on google about Restful web service with WSO2 AM, but I don’t find anything on RESTful part. Could you please help ?
Thanks,
Sayali
Hi Sayali,
This stackoverflow question and answer[1] will help you.
Since API Manager has an ESB underneath, ESB capabilities are also available within API Manager. So this sample[2] is applicable here as well.
[1] – http://stackoverflow.com/questions/12061650/wso2-api-manager-can-it-convert-rest-requests-to-soap-requests-on-the-backend
[2] – https://docs.wso2.com/display/ESB460/Using+REST+with+a+Proxy+Service
Thanks,
Pushpalanka
Hi
We’re facing below errors, could you please guide?
[2015-12-23 20:49:52,657] INFO – LogMediator STATUS = Message dispatched to the main sequence. Invalid URL., RESOURCE = /pizzashack/menu/1.0.0
Unexpected character (<) at position 0.
at org.json.simple.parser.Yylex.yylex(Unknown Source)
at org.json.simple.parser.JSONParser.nextToken(Unknown Source)
at org.json.simple.parser.JSONParser.parse(Unknown Source)
at org.json.simple.parser.JSONParser.parse(Unknown Source)
at org.json.simple.parser.JSONParser.parse(Unknown Source)
at com.pizzashack.client.web.JSONClient.getAvailablePizzaList(JSONClient.java:75)
at com.pizzashack.client.web.MenuItemManager.getAvailablePizzaList(MenuItemManager.java:28)
at org.apache.jsp.index_jsp._jspService(org.apache.jsp.index_jsp:120)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:403)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:492)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:378)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.wso2.carbon.tomcat.ext.valves.CompositeValve.continueInvocation(CompositeValve.java:178)
at org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve$1.invoke(CarbonTomcatValve.java:47)
Hi Pushpalanka,
I followed this site: http://sanjeewamalalgoda.blogspot.in/2015/05/use-openid-with-oauth-20-in-wso2-api.html and get the User Schema details which has details like below
{“phone_number”:”4354353535345″,”email”:”mkyong@yahoo.com”,”family_name”:”Yong”,”country”:”Japan”}
How I will get other claim details with JWT assertion which I configured at Service Provider ? Like you shown in your example?
{
“iss”:”wso2.org/products/am”,
“exp”:1391029971429,
“http://wso2.org/claims/subscriber”:”admin”,
………………
………………
}
Hi Deepak,
This seems to be due to a type mismatch.
The getAvailablePizzaList method in the sample look for a JSON to be parsed and seems what is returned is an XML with < symbol.
Would be a good idea to double check whether pizzashack/menu/1.0.0 returns the expected JSON output.
Thanks,
Pushpalanka