AAD Token caching in APIM best practices - azure-active-directory

We are running a web-app that aggregates data from a lot of providers (Graph, SharePoint, O365 and many other consented aad-based apis.
We route the calls to the respective upstream in our APIMs (Get OBO token and forward the request to upstream).
Our expectation was that the AAD token exchange will be very fast (~200 ms). But we are seeing that it takes around 900 ms on an average.
Since the requests are going from APIM (which doesn't have ADAL Cache), multiple requests from one user to one upstream (say Graph API) gets exchange token (OBO token) several times (for each api hit).
We are thinking of adding a Redis cache to the APIM to cache the tokens.
Before we do that, would like to hear from the experts here,
What is the best way to optimize fetches of multiple OBO tokens. (Eg: Is there a way to fetch more than one OBO token - SharePoint Token, Graph token etc, in a single request to AAD ?
In APIM, what are the token caching best practices. If we add external cache to APIM, what other security measures to be deployed.
Is there any best practices to get the OBO token within 200 ms ?
Thanks in advance

From APIM side I can answer only #2.
You don't necessary need to add external cache, APIM comes with built in cache, just use cache-store-value and cache-lookup-value policies to store and retrieve value. You can investigate received token (parse it using .AsJwt() function) and set cache expiration to a value lower than tokens lifespan. External cache in APIm is useful in case you need more space for cache, or you want to be able to clear it proactively. If external cache is used APIM will use provided connection string to connect to external Redis instance using HTTPS.

Related

Changing AAD accessTokenAcceptedVersion does not result in token version change

I created a new app registration for an app service resource and the accessTokenAcceptedVersion was set to 2 by default (or may be due to my choices). Some clients got an access token for this resource and is being potentially cached on that client.
Later I changed the accessTokenAcceptedVersion to null (i.e. default 1). Now those clients fail to authenticate to the resource (rightfully so) given they have a cached v2 token.
The client in this case is an azure function using the AzureServiceTokenProvider library for getting & caching tokens. So I tried various ways to invalidate the cache involving :
Restarting the function
Waiting out for 1 day (the token expiration time)
Making changes to the app registration
Unfortunately Revoke-AzureADUserAllRefreshToken doesn't seem to work for managed identities.
But I'm still getting a V2 token. What can be done to invalidate this cache or to force a V1 token somehow? I'm trying to do this without any code change currently. But can deploy a change if needed at all.
On other machines/infra I'm able to get a V1 token for the same resource using the different identity. As per my understanding, the token version purely only depends on accessTokenAcceptedVersion. Nothing else.
Please check below points:
If you have changed the accessTokenAcceptedVersion to ‘null’ value, it may also permit v2.0 tokens – It is an issue on AAD’s side. It also depends on the way the app is registered. The difference is that:
If it was done using Azure Portal, then the 'accessTokenAcceptedVersion' field of manifest is set to 'null'
If it was done in the App Registration portal(https://apps.dev.microsoft.com), then it may point to version ‘2.0’
Also check :
The v1 authorization endpoint : https://login.microsoftonline.com/tenantid/oauth2/authorize?
The v1 token endpoint : https://login.microsoftonline.com/tenantid/oauth2/token
Try to change the authority and instance to v1 endpoint in the code and also wherever it is used in the code.
See Microsoft identity platform access tokens - Microsoft identity platform | Microsoft Docs
Both v1 and v2.0 endpoints have their own parameters separately. The v2.0 endpoint expect the ‘scope’ parameter in the request, whereas v1 endpoint expect ‘resource’. So do check the scopes for the api you are referring to and change the code accordingly.
If you still get v2.0 tokens, you must clear the cache of the client application calling your API otherwise until the token has expired, token would be taken from the cache, and would still be a v2.0 token. For that, you may try to call AcquireTokenSilentAsync (in the client while calling you Web API) to force the refresh.
Reference:
Wrong version of access token (got Azure AD V1 instead of V2) GitHub

React & Express JWT Auth: Is it safe enough to store access tokens in Cookies?

I've spent a few days trying to figure out a secure authentication method for SPA/React (client-side).
Most of the tutorials I've read in the wild contradict each other.
One says have to store in Cookies another in Local Storage, one says don't need to use refresh token, one says have to use a refresh token.
I'm building a React SPA app for the frontend and Express for the API (backend). Both are stored in the same domain:
React: example.com
Express: api.example.com or example.com/api
Is it enough to secure my application by using Cookie (access token JWT):
httpOnly:✅
secure: ✅
sameSite: strict
without refresh token
This matches the answer here: https://stackoverflow.com/a/57779076/11340631
The question is:
Is this safe enough?
How long does it take to set the expiration of the access token?
Is this as per Oauth recommendation?: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps
What if my access token is stolen? For example, my friend is using my PC and he stole my cookies and use it in his PC browser.
I really hope to get the answer here, any answer is appreciated.
It's safe against extracting the token with Cross Site-Scripting, but, without other security controls it might be prone to Cross Site Request Forgery (cookies are automatically attached to a request). Is API accepting key in the cookie or must it be sent in the Authorization Bearer header?
My concern is, that if you're not using refresh token, the access token must have a relative long expiration. OAuth2 was not intended to be used to authentication alone, but together with some session-like solution, for example OpenID Connect and SSO.
The shorter the better, unless it can be revoked any time server-side. If there's no way to revoke the key, the 5 minutes expiration date is, in my opinion maximum. That's why refresh token and session-like endpoint is the must.
OAuth is not designed for web application client's authentication at all. That's the common anti-pattern in many projects I've pentested. https://oauth.net/articles/authentication/
I'm glad for your awareness of such a threat. Access tokens must either live very shortly, or they must be revoked server-side in a some way, for example by utilizing some kind of revoke-list. Or the refresh token with server-side-like session endpoint should be utilized.

Client Side Rendering and API Security [duplicate]

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

Token based authentication in spa (React)

As I realized refresh token not supported in spa (react) .
Because it can not protect it .
So series of questions came up to me :
1 - Can we use long time access token in spa ? Is it secure?
2 - Is alternative solution for refresh token?
3 - Should we use the 3rd party identity server such as identityserver 4 or we can implement token generation Ourselves). What is best practice?
A bit late, but still...
You are right in terms of that refresh token should not be returned by Implicit Grant which is used to authenticate users in SPA applications. And yes, the limitation is due to a browser is unable to keep it private.
1 - Can we use long time access token in spa ? Is it secure?
We can, but whether it will be secure would depend on your application's security policy.
To keep it short, here is an example of how you can consider Access Token Lifetime to be specified for various security requirements.
2 - Is alternative solution for refresh token?
Yes, it is called Silent Authentication and briefly it looks like this:
a client (SPA app) obtains an Access Token and expires_in parameter
Identity Server provides an auth session (cookie) so the app can request a new token without providing credentials since it's already authenticated at Identity Server
in case of session's sliding expiration a client pings Identity Server to keep the session alive as long as needed
once the Acces Token becomes expired and auth session is alive (a check might be needed), a client requests for another Access Token (this is usually done in a setTimeout), but in this case providing a parameter to tell an Identity Server that consent screen should be dropped (usually it is prompt=none)
Resources:
Azure AD Silent authentication
Auth0 Silent authentication
3 - Should we use the 3rd party identity server such as identityserver 4 or we can implement token generation Ourselves). What is best
practice?
That would depend on the size of your application and whether you need just a token generation or something more (like Federated authentication out-of-the-box, various grant types, etc.).
For big enterprises (if there's no need to reinvent the wheel) it is always the best practice to use a production-ready 3rd party library (Identity Server 4 or OpenIddict) unless you have a small application (MVP, prototype, etc.).
Identity Server 4 needs some effort to configure it the right way and may simply be excessive. OpenIddict is a bit easier alternative.
Custom token generation is something that we used to do before Identity Server emerged. Today it is only a matter of having a quick solution for your custom authentication needs.
Worth to mention this project JWTSimpleServer for simple JWT authentication.

Session Token Authentication Security

I need some advice regarding using session tokens to authenticate users. I am building an AngularJS app which uses an API to tie in with the backend. I am only building the front end, not the backend. The documentation states that all calls to the API have a session token attached in the body of the request (POST).
I would like to know about the security of storing this token in localStorage. That is where I am storing it now and retrieving and attaching it to each API request. After login, the server sends the session token in the body and I save it from there.
There is no documentation about an x-access-token header that should be sent with the request made to the server. It is not being checked server side. What are the implications of this? I feel that it is susceptible to attacks without this added layer of security.
My main concern is the security of this setup. I want to know what the best setup is to make sure this app is as secure as possible and recommend changes to the way the backend is setup to facilitate this.
Thanks!
As you tell, you are only working on the UI part and not the backend. It is up to the backend team to ensure headers are properly evaluated and security is enforced (btw request headers do not belong to request body). Just put the token into the x-access-token header as they tell.
Storing the token inside the localStorage gives you a little more control over the cookie: You will not accidentally send it to unnecessary URLs. However, older browsers do not support it - you may need to use a shim for that.
In a case of SPA, you may consider not storing the token at all: It could be fetched each time your application is accessed and then stored within a service in angularjs, but it depends how your fetch/login operation is implemented (is it always interactive, how long does it take, etc).
I would suggest use $cookies rather than localstorage. As localstorage does not support some legacy browser.
I am using cookies to store token in my project

Resources