Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert
You’ve reached the very right blog for you,
If you see this:

Forbidden


And:
If you hate it

In this blog, we’re going to learn how to do troubleshooting when we get the Forbidden

Of course, this blog covers only scenarios reaching out to SAP Cloud Platform Backend service, as described in this series of tutorials

What is the problem?


We’ve created an API with SAP Cloud Platform Backend service.
As we’ve learned  (e.g. here) the APIs are protected with OAuth (see here and here for explanations)
This means, when such a resource is requested, an access token has to be sent
But what, if we get an error response?
The error message could be:

Forbidden


What now?
How to find the reason?
How to fix?
Troubleshooting is easier, if we open a URL and get a user-login screen. If login fails, we know we’ve entered the wrong password (or wrong user)
But if we send a token…. How can we know?
We can look at a token:



No matter how long we keep staring at the token: we will never be able to guess what's wrong with it...

What is OAuth 2.0


The OAuth 2.0 specification describes:
There’s a “Resouce Server” which offers data e.g. via a Backend service API
There’s a user who wants to view it
There’s a “client” tool used by the user
There’s an “Authorization Server” which knows the user and the roles of the user
As such, when  the user wants to open the resource, the “client” tool delegates the login to the
“Authorization Server”
The “Authorization Server” verifies the login for
- correct user and password (authentication)
- user has required roles (authorization)

To verify that, the server might connect to an Identity provider (depending on landscape)
If everything is fine, then the “Authorization Server” issues an “access token”
The client sends this token to the “Resource Server” in order to access the protected resource
The “Resource Server” knows how to check the token (it might connect to the “Authorization Server” to check validity) and responds with the requested data.

Why is this cool?


Because no involved component has to know the sensitive data like user and password.
The “client” never sees and stores the password, because it delegates to “Authorization Server”
Etc
Only the access token is sent over the net
The access token usually expires quickly, so even if it is stolen, it cannot be reused

What is a token


The OAuth 2.0 specification doesn’t describe how the token should look like (only how it is used )
It doesn’t describe the format, so it is up to the implementation of “Authorization Server”
The token is a string
The string contains some small pieces of informationThe token type is usually a “Bearer” token, which means that anyone who “carries” it, can access the resource
The token is not encrypted
It is only encoded.
For security reasons, it is signed, and it should be sent with TLS (Transport Layer Security)
Usually, when decoding the string, we get a JSON object
This means that usually, the token format is a “JWT Token”
"JWT" stands for "JSON Web Token"
The “client” doesn’t care about the format, it is just sent to the resource
As for the users, we care even less about it, as we never see it
BUT: only in this blog, we do see it

How can we troubleshoot a JWT token


As we’ve learned above, the token contains the information about user and roles (among other pieces of information)
So, for troubleshooting, we’d like to know this info, such that we can verify if it is correct.
What we want to do is to VIEW the content of the token.

But first we need to get a hold of the token

How to get the token


The token is just a string, easy to copy&paste

If you were following this tutorial, you’ve seen the token in the browser window.
You can just copy&paste it

If you have an application running in the cloud, e.g. node.js, like described here or here, you can add a log output
console.log('Successfully fetched OAuth access token: ' +  result.accessToken);

then copy the token from the Cloud Foundry log

Note:
The Cloud Foundry log can be accessed from Cloud Platform Cockpit or via command line (using command: cf logs <appname> --recent)

Note:
Above snippet is copied from here

How to view content of the token


It is easy, we just need to decode it.
There are online tools which do the decoding of JWT tokens for us
I’ve tried e.g. this one https://devtoolzone.com/decoder/jwt
And here’s how the content of a JWT token looks like:



Note:
If you’re wondering about the cryptic abbreviations, used as property names:
These are the so-called “claims” and JWT recommends short names, in order to keep the whole JWT token short
Some claims are registered as default (see spec), others are specific to e.g. OAuth implementation

How to read JWT token programmatically


If you’re working on an application and you get a hold of the token, you can proceed easier:
Instead of copy&paste the token into a decoder tool, you can decode it yourself, in the code.
So you can directly view the interesting values in the Cloud Foundry log
The following example shows how it is done in node.js
The example is taken from  this tutorial, where we receive the forwarded token in the “Authorization “ header:
var theJwtToken = authHeader.substring(7);// removes 'bearer ' from string
// decode JWT token
var jwtBase64Encoded = theJwtToken.split('.')[1];
var jwtDecoded = Buffer.from(jwtBase64Encoded, 'base64').toString('ascii');
var jwtDecodedJson = JSON.parse(jwtDecoded);
// print useful information: user, scopes, roleCollections
console.log('User: ' + jwtDecodedJson.user_name);
console.log('Scopes: ' + jwtDecodedJson.scope);
console.log('Role Collections of user: ' + jwtDecodedJson['xs.system.attributes']['xs.rolecollections']);

How does this help?


You can check the following information for correctness:

Scope:
If you want to access a Backend service API, the JWT token needs to contain the required scope:
"scope" :  [..."Backend-service-..." ... ]
If you don’t see it, then the used XSUAA instance is not properly configured

user_name:
You can check if the user is as expected

xs.rolecollections
You can check if the user has the required role collection assigned
In the JWT token, we can only see the assigned role collections, but not the individual roles contained in the collections

Identity zone
You can check if the target API and the JWT token belong to the same identity zone.
In other words: if both are located in the same subaccount

client_id
Here you can check if the “client” which is registered at “Authorization Server” (in OAuth terms) is the same like the one which you’re using the code dealing with the OAuth flow
To fetch the token, the clientId has to be passed
See here for a code example for handling the OAuth flow

How to continue shooting?


After checking the content of the JWT token, you might need to check the following:

XSUAA params:
If JWT token doesn’t contain the required scope, make sure to create an XSUAA instance with correct parameters.

Binding:
Make sure your app is bound to the correct XSUAA instance. It can easily happen that you bind your app or approuter against a wrong service instance.
I guess it is a good practice to store the XSUAA parameters in a file called xs-security.json, in the application folder (as described here). Like that you can be sure to use the params required by that app

User Role:
Go to Cloud cockpit to view the role collections mentioned in the JWT token
Is the required role contained in one of them?
The required role is the one defined by Backend service. It has to be assigned to your user (see here)

Note:
If the error still occurs after fixing the problem:
You might need to logout and login again, or deeply refresh the browser

How do errors look like?


Error Message:
Forbidden
Status code 403
(see here for definition of 403)
The user doesn’t have the role which is required by Backend service

Error Message:
"You do not have sufficient authorization to access API with name PRODUCTSERVICE..."
The user doesn’t have the role which is required by Backend service

Error Message:
Forbidden
The user doesn’t have the role which is required by App Router

Error Message:
“Authentication object was not found in the SecurityContext”
This error message is sent by Backend service if the required scope is not contained in the JWT token

Error Message:
“Authentication object was not found in the SecurityContext”
Same error message is given by Backend service if no JWT token was received at all

How can I get the Links?


OAuth 2.0 spec: https://tools.ietf.org/html/rfc6749
OAuth 2.0 Bearer token usage spec https://tools.ietf.org/html/rfc6750

About JWT: https://jwt.io/
JWT Spec: https://tools.ietf.org/html/rfc7519
Example for JWT token decoder tool https://devtoolzone.com/decoder/jwt

How can I report Errors?


Just post the error and the resolution in the comment section.
Or send to me via personal message
Errors Welcome!
6 Comments