Automated code for getting access token

I am not sure if this is doable for a web. Say if I use ueberauth or pow assent to connect with microsoft graph API. From microsoft doc, they mentioned that the access token given is only limited to 1 hour.

Provided I store the minimal user info in my database (along with access token/refresh token), is there anyway I can execute a http rest api command every 30 minutes in background to get new combination of access/refresh token?

I’ve published not long ago the OAuth2TokenManager library that does that.

Documentation is a bit sparse, what is not shown in the examples is that you have to register the refresh token first using OAuth2TokenManager.RefreshToken.register/5, with the "sub" field set if the token cannot be introspected.

Also the backend for storing tokens is based on ETS + DETS, you might want to implement your own (DB…).

2 Likes

Thanks for the reply.

From what understand, after the client connect to my web app using pow assent/ueberauth, I have to register both ‘refresh_token’ and ‘access_token’ using the OAuth2TokenManager library right?

Does the automated request for new ‘access_token/refresh_token’ is being handled as well, or need to be set from ‘elixir code’ to invoke the library function? Because I believe most apps have different expiration duration and I am not sure how to do the automated part (when to invoke the function to get new token pairs)

Yes.

To see what happens on the wire in dev, you can activate the Tesla Logger. Useful to check if the token is correctly introspected.

Yes, it checks if there is a valid access token for the given scopes using expiration time and requests a new one using the refresh token if there’s none. It implies the access token was registered with an "expires_in" field or the access token was successfully introspected, in which case the "exp" is used to determine the access token’s end of validity. At least this is how it should work, if not, open a PR :slight_smile:

Also note that they can be several valid access tokens for one refresh token. If you use scopes, the best practice, called the least-privilege principle, is to use access token with just the scopes you need - no more.

You still have to manually request a new access token when the API answers that the token is invalid. Could happen if the access token is revoked, the API has “lost” it, etc. In this case the API should answer with a 401 or 403 error code following RFC6750: 3 - The WWW-Authenticate Response Header Field if it is OAuth2 compliant. Guess it’d be a good use-case for a Tesla middleware.

3 Likes

Thank you very much.

I will try to implement using your library

Considering those security recommendations, I wonder if it’s safe to store the refresh token in a dets table and the access token in a public ets?
I would consider a refresh token as a piece of sensitive data, but maybe I’m overthinking it or being paranoid.

Regarding the original question, although I haven’t really thought it through, wouldn’t it be possible to launch a GenServer Under a dynamic supervisor when a user logs in, with the current access token and refresh token, send to self a refresh message every 30 minutes and stopping it when the user logs out? You would have to either store the pod somewhere or use some sort of registry and obviously follow the aforementioned recommandations for gen_servers with sensitive data.

Of course this would provide less features than @tangui ‘s library.

A refresh token is indeed sensitive. The ETS & DETS backends are mainly for testing purpose and quick prototyping. It can also be stored on an encrypted drive.

Note that sensitivity depends on the granted scopes. Read-only scopes might be less sensitive than write scopes (like writing on someone’s wall on Facebook, Twitter, etc.).

That said, a refresh token can be granted for a long time (several weeks, months) or even indefinitely, so it often needs to be persisted.

In the OAuth2 standards, there are no requirements to delete a refresh token upon user logout. Actually, there’s no relationship at all between tokens and user session. In the OpenID Connect standard (a superset of OAuth2), it’s quite unclear but the consensus from implementers is that the refresh token has to be deleted when the user logs out, except if the "offline_access" scope was requested with the other scopes.

True, I had OpenId in mind (since I’m working with keycloak atm) and tend to think of “offline_access” tokens to be different than mere refresh tokens (for the same reason).
Thanks for the correction.

1 Like