Caching refresh tokens using ADAL v3 and Windows Credential Manager - vsto

I have a VSTO plugin and I want users to log in with AAD so it can access downstream services but to reduce the number of login prompts I would like to cache the refresh token in Windows credential manager.
I believe ADAL v3 doesn’t allow refresh tokens to be accessed so I would appreciate any advice on how this might be achieved. Is there a token cache that wraps accessing the credential manager in Windows?

ADAL v3 .NET saves refresh tokens in its in-memory cache. If you want to have them persisted, you can save the entire cache by providing a custom cache class that saves it as a blob in whatever storage you choose, including the cred manager (tho the challenge there is that you need to shard the cache to deal with the fixed length of the credman entries). See the client portion of https://github.com/Azure-Samples/active-directory-dotnet-native-desktop

Related

How to safely persist an oauth2 access token in my add-in

This question might be a duplicate of this one but I believe it was not properly addressed and I have come up with the same concern a year later.
I'd like to use my own oauth provider authentication flow, and I'd like to understand what's the best user flow for getting the token from my server.
According to the documentation, we need to use the displayDialogAsync method to open the oauth screen, which will send the authentication code to the backend, which it can decode and create a token that can be used for the Office add-in frontend.
However, there's no indication on how the backend can send this token to the frontend. Since setting a token cookie will not make it accessible from the add-in side. It seems the only way to grab it is by redirecting from the server to https://localhost:3000/oauthResult/index.html?authToken=XXXX. And that route can somehow store the token somewhere and then close the dialog.
So my main two questions are:
How to safely send the access token from the backend to the frontend without using a redirect with a cookie
Where to safely store within the Office Add-in ecosystem so that it can be picked up both by desktop and web clients? I know that I shouldn't use the Settings object to do so.
I tried using a redirect from my backend to my add-in frontend with the auth token set in a cookie, but that cookie was not available to be read from the add-in side later on.
For your inspiration, see Caching in MSAL. MSAL.js is the Microsoft Authentication Library for JavaScript. MSAL.js is using the Web Storage API and can be configured to use either sessionStorage, localStorage or memoryStorage. As the article describe, the choice between different storage locations reflects a trade-off between better user experience vs. increased security.

Where to store Access and Refresh tokens when consuming external APIs using IHttpClientFactory. Net Core

I am using IHttpClientFactory for sending requests and receiving HTTP responses from my Web API to an external APIs using Net Core 2.2.
The access token and the refresh tokens used to send the request to the API have been stored in the appsettings.json. When a request returns 403 or 401 errors, I get a new token dynamically and add it to the header of the request.
But How Can I update appsettings.json with the new access and refresh token in order to use it for subsequent requests.
Is It there a much better approach to store access and refresh tokens than the appsettings.json?
Since you are using IHttpClinetFactory (and assuming you are using Typed Client as well), you can create your own HttpMessageHandler which would be triggered before any request made by your Typed Client and link it with your typed client via DI like this:
services.AddHttpClient<IServiceContract, ServiceImplementation>()
.AddHttpMessageHandler<TokenHandler>();
Inside that TokenHandler you can check if the request has a token in the headers or not. If not check the cache (Memory Cache) for available tokens, then validate the lifetime of the token.
If the token is expired or there is no such a token in the cache, issue a new one and store it in the cache.
I am sure there are better ways, but that what I would do.
Note: If your application is distributed on multiple servers, then use Distributed Cache instead of the Memory Cache. You can add either easily via DI.
Update:
You can register your handler like this:
services.AddTransient<TokenHandler>();
Giving the hypothesis your client WEB API connects automatically to your external APIs (and also, ask automatically the tokens), you don't need to store tokens and refresh tokens.
Your webservice needs to keep the tokens in memory (in a singleton) and use it whenever needed.
When the external API wants a new token (e.g. after token expiratoin), you just need to ask a new one and update your singleton.
We use this way of working for several projects and it's reliable.
In general, you should store the token in database for permanent save by EF Core or any other data provider.
If you insist on saving in the appsettings.json, you need to implement the custom feature.
For a demo, check Manually trigger IOptionsMonitor<>.OnChange

How are you supposed to store access tokens?

We are building an application with a React/Redux frontend and a NodeJS/Express Backend. I, not being a security expert, opted to go with Auth0 to handle Authentication.
Auth0 returns an ID Token and an Access Token when a user logs in, this access token is used to authenticate and access our backend API.
We've seen this Access token stored before in Local Storage but Auth0 then contradicts that here. Furthermore, in this answer it seems that some recommend storing in Local Storage, as does this one.
This has me terribly confused. How can we store and persist the token without storing it in memory? We could store it in Redux only but it'll clear on refresh which isn't a solution.
Here they show that the User Signs in and the Access Token is returned and that later it is to be sent along with API Requests, which I understand, but where is it to be stored in the meantime?
How are we supposed to store the access tokens so our application can access our API? Or are we not supposed to store it at all?
We decided to store access tokens in a React Context Provider. Looks like Auth0 has updated their quickstart guide to do the same.
The best way to store AT/RT is by using a distibuted cache memory for your client backend servers. By this way, you make sure that all API calls must transite by your backend application. In your frontend, you pass only the ID_Token witch has to be used to identify your end users.
User sends ID_Token --> Client (backend web app) checks the Id_Token and Get AT from cache memory --> Call the APIs with AT.

How to use Google APIs without continuously explicit user consent from a progressive web application?

I have a progressive web application that needs write-access to the Google Drive API for uploading data (media files) the user is creating (either online or offline) in the background while online. It does not really need a server (except for serving the required files, so a static server is sufficient), all of the work could be done on the web application client side.
Since uploading needs to happen on the background, whenever the user is online again (using a service worker and the background sync one-shot API), an access token is not enough for my need (the user can be offline/not use the web application for days) and a refresh token is not supposed to be stored on the web application client side, as far as I understand. Even if it were, I would still need the client secret, which means I have to use a server (or keep the secret within the web application client side, which is a no-no) in order to refresh the token.
It seems like the current ways of using the OAuth2 scheme are at odds with server-less progressive web applications, or I might be missing something. Progressive web applications are more like Chrome applications in this regard, I guess, but I have to supply a Chrome application ID in the Google API console for my application, which I do not (and do not intend to) have and Chrome applications use the Chrome identity API for getting the tokens, which I do not intend to use (and cannot).
I am currently using an actual Node.js server which takes care of the authorization step, keeps the access token and refresh token in a database and returns the existing or new access token to the client, whenever asked. The server is redundant here (and requires a privacy policy for this data which I really do not need to store), I want to do everything using client code, without continuously asking for authorization whenever I upload in the background.
Keeping the refresh token on the web application client side and just reaching out to the server for actually refreshing the access token (nothing must be stored in the server side except the client secret, which is fine), but like I mentioned, I understand the refresh token is not supposed to be kept on the web application side.
Is there a safe and secure way to implement this without a server (or with a server that only gets the refresh token and returns it to the client and refreshes the access token by getting the refresh token from the client)?
It's actually fairly simple, depending on the fine details of your use case.
An important factoid is that once a user has granted permission to your app, he will not have to re-grant it. So you don't need to "continuously asking for authorization whenever I upload in the background". However, the only constraint is that the user must be logged in to Google in order to obtain an Access Token. Normally this isn't an issue, but your app needs to deal with the scenario that a user has logged off from Google, and prompt for login.
All the details are here https://developers.google.com/identity/protocols/OAuth2UserAgent
I suggest avoid the Google JS library because (a) it has its own opinions about the UX, (b) wasn't written with PWAs in mind, (c) has issues on mobile, and (d) is closed source so when it breaks (as it does occasionally), your users are dead in the water until Google fixes it. The page above details the OAuth endpoints so you can easily use them directly. This has the side benefit that adding other cloud storage accounts (AWS, Azure, Drop, etc) is just a case of changing the endpoint URL.
The architecture I use in my PWA is to have my PWA prompt once (and once only) for authorization and then store the user's Gmail address in localStorage. I then have a
hidden iframe which polls once per hour for an Access Token, using the gmail address in a login_hint. This means the iframe is never required to present any UX. The only time UX is required is for the initial auth, which is of course unavoidable, and once per session if the user has logged out of Google.
The only other edge-case you might want to deal with is allowing the user to select between multiple Google accounts, say a personal account and a work domain account.
On a broader point, remember that Google didn't create the OAuth spec so there is little they can do to provide an alternative solution. At an abstract level, auth requires one of the user being present, or secure storage for a permanent token (eg on a server or within a secure store such as Android). Even if we invent OAuth 3, that will still be the case.

Persist Authentication in Web App with Power BI

I have a web app that is using the Power BI Web API to display some dashboard data, inside another application. I have followed the authentication examples on GitHub, and can authenticate and query the API.
HOWEVER, all of the examples store the returned tokens in temporary storage (e.g. session), which means that the user has to re-authenticate the application every time they visit (or the app pool restarts).
Ideally, I want to authenticate the web app when it's set up (using a set of credentials set up just for the app), and then have the web app continue to use the same credentials, without the site users having to log back in to Power BI again (as many of the users of the web app do not have direct Power BI access).
Is this possible? If so, how might I go about it? All of the examples I can find are such that you have to re-authenticate every time you access the API. I suspect because I don't know the correct terminology here (this is my first time using the AAD services and authentication) I may be missing something obvious.
To do what you want, you need to securely store the refresh token. The call to get the initial token should return both the accessToken (that expires within 1hr usually) and a refreshToken that you can use to get new accessToken. The refreshToken is usually valid for 90 days, so your access is not indefinitely. There's documentation on MSDN for how to do that:
https://msdn.microsoft.com/en-us/library/ff752395.aspx