OAuth with SAP API Management (HCP) – Part 1
When considering the implementation of an API Management project, there are many ways to do Authorization. In a digital world, OAuth (especially in version 2.0) has widely used mechanism for cross-domain authorization. If you are serious in implementing an API-driven infrastructure to deliver Apps to customers, there will be no way around OAuth.
Let’s take a step back.
What is OAuth? A specification.
What does it do? It specifies how to “enable a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf.” (taken from the specs).
The IETF Document is quite readable, and is worth bookmarking to understand all of the spec’s details.
For an overview about OAuth, there are plenty of websites out there. An good overview is available on DigitalOcean, where the concepts and the flows are well explained.
In this blog entry, we’ll cover a basic scenario of OAuth: the “Client Credential” flow (or “two-legged” flow because only 2 parties are involved). This flow is used when the application is also the resource owner, so there is no user involved in this grant type flow.
First of all, I will assume you are acquainted with SAP API Management from our public cloud (HCP), and generally acquainted with web technologies. Also, we’ll use POSTMAN to do all the testing.
If not, please consider going through a good tutorial first of all.
The main idea behind this tutorial is to implement a “client credential” flow using the SAP API Management components.
The diagram below depicts the various steps to get there.
1- we will create an API Proxy that will be our “token endpoint” (using the OAuth policy). This API will generate the access token for instance, but could also revoke or refresh tokens.
2- we’ll create a dummy API proxy, to be the protected resource (using the OAuth policy).
3-we’ll add the dummy API proxy to an API Product
4- we’ll create an application and add the API Product created in step 3. This application has an application key and an application secret, corresponding to the client_id and client_secret required by OAuth to generate the token.
5- we’ll now use our token endpoint to get an access token, using the credentials of the application
6- finally, we’ll use the access token to get access to the protected resource, the dummy API proxy.
Remember that SAP API Management is a framework with a lot of predefined stuff, so we can implement virtually any behavior, or flow.
1- Create the Token Endpoint
First of all let’s create the token endpoint in order to generate the access token.
Create a new proxy, and call it “OAuthService“.
Because the endpoint of this proxy will be the OAuth policy, simply set the target endpoint to be any URL (http://none.com for instance).
Add a “Resource” that we’ll call “GenerateToken” for instance. This is the path we’ll call when we want to generate a token. Note that is has to be a “POST” because we will be sending the credentials as x-www-form-urlencoded body to the endpoint.
Now open the policy editor and add an “OAuthV2” policy in the “GenerateToken” flow.
The OAuthV2 policy is a multi-purpose policy: depending on how you configure it, it can generate, invalidate, verify, refresh, etc. OAuth tokens. For more information, have a look at the help.
In our case, we will configure it, so that it will return an “access_token”, ie. generate a token when requested.
The configuration of the OAuthV2 policy is available below:
<OAuthV2 async="false" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt"> <Operation>GenerateAccessToken</Operation> <GenerateResponse/> <SupportedGrantTypes> <GrantType>client_credentials</GrantType> </SupportedGrantTypes> </OAuthV2>
Your token endpoint proxy should look like this:
Note that the execution of the proxy above will be stopped after the OAuth policy is triggered, not reaching the dummy host we have defined in the first place (normal behavior of the “GenerateResponse” configuration tag in the OAuthV2 policy).
Also note that the order of the configuration XML elements is important. The OAuthV2 policy XML configuration should have the elements configured in the following order:
2- Create a dummy API proxy
Our next step is to create the resource that will be protected by an OAuthv2 policy, ie. the requester will need to provide an access token.
For this exercise, we will not proxy an actual API, but stop the execution in the API Management layer. To do so, we’ll define a specific “route rule” that will not point to a target. The response will be generated from with the API proxy with an “assignMessage” policy.
First of all, create an new API proxy. name it “OAuthTestProxy” for instance.
Once the proxy is created, switch to Edit mode and generate 2 resources: Test1 (only “GET”) and Test2 (only “POST”). We will use these resources later.
Also in Edit mode, delete the default route, and create your own one, which target endpoint shall be “NONE”.
Eventually, your proxy should look like this:
Now we will add a response for the resources we have created. This is done by using an “AssignMessage” policy, which can assign values to request or response elements such as headers, parameters, body, ….
Go to the Policy Editor, and add an “AssignMessage” policy in the Outgoing flow of your “Test1” resource.
To do so:
– click on the “Edit” button in your policy editor
– click on the “Test1” resource on the left side og your screen
– click on the “+” button next to the “AssignMessage” policy on the right.
Name the policy “SetResponse” and select “Outgoing Response” as stream.
Click on “Add”.
Now configure the policy to return a message to the caller:
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'> <!-- Sets the converted json to the response --> <Set> <Payload contentType="application/json">Test1 - GET Response</Payload> </Set> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <AssignTo createNew="false" type="response">response</AssignTo> </AssignMessage>
Do the same for the “Test2” resource, and use another response:
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'> <!-- Sets the converted json to the response --> <Set> <Payload contentType="application/json">Test2 - POST Response</Payload> </Set> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <AssignTo createNew="false" type="response">response</AssignTo> </AssignMessage>
Test your policy by using postman.
Your URL should be composed as follows:
HCP API Management URL, followed by the URL of your proxy, followed by your resource name:
“http://myHCPTrial” + “/v1/OauthTest” + “/Test1”
Remember to use “GET” or “POST” methods for your 2 resources.
Add OAuth token verification policy
We will now add the OAuth access token verification policy to our API Proxy.
This policy is not tied to any resource, and shall always be executed at the very beginning of the request. hence we’ll place it in the “pre-flow” section.
To do so:
– click on the “Edit” button in your policy editor
– click on the “PreFlow” resource on the left side of your screen
– click on the “+” button next to the “OAuthV2” policy on the right
– name the policy “VerifyAccessToken” and set it toe the “Incoming Request” stream
– click on add.
Now configure your policy to check the OAuth token:
<OAuthV2 async="false" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt"> <!-- this flag has to be set when you want to work with third-party access tokens --> <ExternalAuthorization>false</ExternalAuthorization> <!-- valid values are GenerateAccessToken, GenerateAccessTokenImplicitGrant, GenerateAuthorizationCode , RefreshAccessToken , VerifyAccessToken , InvalidateToken , ValidateToken --> <Operation>VerifyAccessToken</Operation> <GenerateResponse enabled="true"/><SupportedGrantTypes/> <Tokens/> </OAuthV2>
As you can see, we are using the same policy as for the OAuthService (OAuthV2 policy), but with an “Operation” of type “VerifyAccessToken”.
Click on “Update” and on “Save” to save and deploy your proxy.
We now have all proxies in place. In Part 2, we will add the dummy proxy (resource) to an API Product and an API Application, and get an access token with the Applications ID and secret.
A quick question. I do not see the API Management service in our HCP instance. I assume thus that it is a product we have to buy?
sorry for the late reply!
Indeed: if you want to have API Management in your productive instance, you will need to buy the service.
However, you can still use our free trial environment to test all features (almost all features): https://account.hanatrial.ondemand.com
could this method also used be used in a mobile scenario (call the API from an mobile ios or android application)?
I'm kind of stuck because I tried this but I have to provide an authorizeUrl, accessTokenUrl and a CallbackUrl and I don't know which are these items in this current constelation.
Furthermore I thought that maybe I can use the standard OAuth 2.0 standard cloud service but I can't figure it out how to use it with SAP API Management.
when you are talking about "this method", I assume you are talking about "Oauth Token authentication".
You can, and should, use OAuth authentication also for mobile scenarios. I simplified the tutorial using Postman, but you have to think of it as a mobile device for instance. Indeed, OAuth Tokens are not bound to a browser (unlike SAML) and facilitate identity federation in a cloud-world.
Note that Andreas Krause has written another blog that may help you getting started with a 3-legged flow: https://blogs.sap.com/2017/07/12/implement-facebook-login-on-sap-api-management-part-1/
Regarding your issues with the URLs, I am afraid I can't really assist. I did my best to describe everything in detail and it seems to be fine with other readers. Maybe someone from your team/department can have a look on that woth you?
Lastly, I have never used the OAuth 2.0 standard cloud service, but keep in mind that OAuth is a specification, hence the consepts of using an OAuth service will be the same. Regarding the details, I would not know.
Thanks for this blog.
Just one query.. Can we use below URL'S to generate access token and then validate in API?
the OAuth Service of the SCP is not the same as we have in API Management.
So I guess you can use the URLs from your screenshot, but then API Management won't be able to validate them out-of-the-box: AFAIK only the OAuth tokens issued by API Management can be managed and validated by API Management.
Thank you for the quick response.
Yes you are right..API management does not validate these access tokens directly.Need to find a way.
Ah great, I was looking for this answer all over the internet. Thanks a lot. Would be really great if this could be implemented!
I have followed the step by step of your post, I get the access_token but when I call the protected resource it gives me the following error:
On the other hand, what would be the “Route Rule condition” since the value indicated in the image of the post is an invalid entry.
it’s always difficult to help remotely – and regarding blogs almost 4 years old ?
But I just did a quick test, but setting the “default” route to “None” without any condition worked for me.
Hope this helped!
Even I have the same question as Miguel on Route Rules Miguel.
you may want to check my answer to Miguel then 😉
Suppose this solution is for the scenario of APIM acting as the authorization server.
We have a requirement that a Azure front-end app which already got a AAD issued JWT token needs to invoke an OData service API proxy resides in SAP APIM.
Could you please help to let me know where should the OAuth access token be obtained and the design?
not sure about your question... you are saying "[we have an app] which already got a AAD issued JWT token". And then you say "where should the OAuth access token be obtained".
So I will assume that your OAuth token (JWT in this case) is obtained from AAD. When invoking an API provided through SAP API Management, you can verify this token against AAD. This is predefined through an SAP API Management template that you can view here. From within your SAP API Management API Portal, you can download this template ("Discover" menu point) and use it in your API proxy. Also look at the "Overview" of the API Policy Template: it will give you high-level guidance on how to use it.
More detailed information can be found in Divya's blogs: https://blogs.sap.com/2019/09/02/blog-series-json-web-tokens-jwt-verification-policies-in-sap-cloud-platform-api-management/
Great thanks Sven for the comment !
Since SAP ABAP(NWGW) is not able to accept JWT directly instead of SAML assertion bearer for end-to-end OAuth in this case, does that mean APIM needs to convert the JWT to saml assertion bearer, push to NWGW then get the access token?
if the answer is 'yes', how to convert the JWT to Saml in APIM policy, any best practice?
I am no integration developer so I cannot really provide best practices.
But basically, you want to verify your OAuth token in APIM and create a SAML assertion with the OAuth information.
This is well documented here: https://blogs.sap.com/2020/05/13/single-sign-on-sso-personalized-user-access-to-sap-apis-and-the-application-you-can-build-with-it/
If you are looking the the policy template of Step 5, it is available here: https://api.sap.com/policytemplate/Principal_Propagation_via_SAML
If this helps, feel free to "like" my answer so that people know it was successful for you 😉
Thanks much for the tips and advice, that really helps for confirming our scenario design and direction!
I API-M do we have any limitations in Token Factory to issue the number of access tokens to a respective Application?
Also can 1 OAUTH Proxy service can support multiple API-M Applications using it parallelly at the same time.