I am building a glass app using the PHP sample app as reference.
To my understanding, the glass app is a web app which is user facing. When the user visit the web app, they will authorize the web app (using oauth2) to access their resources, and once authorization succeeded the web app will get an access token, which is then saved in a sqlite database (there's this store_credentials() function which stores the access token).
So if I have 100 users who visit the web app and register, the database will hold 100 access tokens for these users. Let's say I have some backend code which pull from a RSS feed every hour, and whenever I find there's a new story I will push it to all registered users. Let's say I have a cron job which does this, when when this job is triggered, I will find all the access tokens in the database and use them to make mirror API calls to insert cards. But what if some of the access token is expired when I am trying to make the mirror API call? It seems I will need to ask user to re-authorized, but at this point I am not interacting with the user. If I have a refresh token, I may be able to call oauth again to get a new access token.
Thanks.
You pretty much answered your own question - when you request permission using OAuth, you should also request "offline" access. The first time you do this for each user it will give you a refresh token along with your access token, and you should store both. If you did not request offline access initially, you will need to revoke the tokens that have been granted and re-grant them with offline access.
If the sample app you're referring to is the one at https://github.com/googleglass/mirror-quickstart-php, all this should be done for you already with the libraries included. The credentials returned from $client->getAccessToken() in oauth2callback.php should include both the access and refresh tokens, and these are saved in that same file by calling store_credentials(). The client libraries should check if the access token has expired and, if so, it gets a new one with the refresh token before making the call.
You may want to take a look at the contents of the credentials object at these various points and make sure there is a refresh token. If not, try revoking all the tokens and starting again, since it sounds like the first time you authorized the client you did so without requesting offline access.
If you are doing this yourself, best practice is to either refresh the access token if it has expired or is about to expire (since there may be some delay) before use, or (even better) attempt to make the call with an access token and, if it fails with an authentication error, get a new access token via the refresh token and try again.
Related
I have an implementation of IdentityServer4 which connects with Azure AD for authentication (OIDC). In the callback method, using the IdentityServertools, I am generating the access_token and redirecting the user to SPA with the same. The SPA then stores the access_token into localstorage and uses it for authentication.
Normally, when my SPA app hits the token endpoint of the IdentityServer4, it gives access_token and refresh_token and then uses refresh_token to re-authenticate a returning user.
In this case of SSO with Azure AD, do I need to generate refresh_token manually? If yes, I can build on top of default implementation and that's not the problem (However, the docs suggest against of changing the IRefreshTokenService implementation or building something from scratch)
My real question is, is there a need of refresh_token here? Because refresh_tokens are stored in DB and never get's deleted and after sometime, these refresh_tokens table will swell (right now it already has 80k rows). The user is expected to click on a small tile inside SAP's Successfactor - that will open the signin/consent screen of Azure or will directly take the user to the main page where zhe will just answer a question and done. So it's hardly 2-3 mins business. So I can continue to generate access_tokens from my IdentityServer4 for every click as I don't expect the user to stay authenticated in the browser if zhe has logged out from SAP's Successfactor (or any other app linked with Azure).
Please advise, if I should generate refresh_token? Is it a good architecture?
Access token is used to prove the request is allowed to access the resource(such as api from ms or your custom api) and refresh token is used to refresh access token to make sure the access token isn't expired. Access token will expire in an hour by default and refresh token has 90 days.
At this point, we can easily find the refresh token is designed for some special scenarios because the expired time for refresh token is much longer than access token's expired time, but we can also generate a new access token in other way such as using msal or sign in again.
As you said in the question, you can generate an access token by one click and you don't expect users to stay authenticated for a long time. So I think it's unnecessary for you to use refresh token.
So we have an application that allows you to create a xml file that runs the app again at a later stage (which may or may not have a user in attendance). Files are stored on the user cloud drive platform of choice. So the process is
Workflow 1
Authenticate to cloud with User 1 details/input
Select files to Download and use
Save and encrypt file metadata and Refresh token to xml file. (app workflow 1)
Workflow 2 ( can be repeated multiple thousands of times)
Send xml file to another pc with User 2. (either by email or remotely through a console
that pc then runs under user 2
start app
App authenticates automatically using refresh token saved in xml file with no user input (as there is a very high chance of the user who created workflow 1 not being in the same city as where workflow 2 is running
Downloads files
applies files (app workflow 2)
PROBLEM
all other platforms we cater for (Dropbox and google and onedrive) gives us access to the refresh token and allow us to authenticate with it again , however the onedrive for business (graph sdks) give us a Token cache which is session based?
Questions
So I need to know how I can get the refresh token from the Token Cache so we can reuse it at a later stage. (yes I'm aware that it will expire after 6 months which is acceptable) .
When i have the refresh token how do initiate a call to refresh the token
Further note - I have managed to handle all platforms before Within silverlight (where the sdks are not supported) through directly calling the rest api calls but we are converting our solution to WPF and would want to use the sdks
thanks
I assume you were developing Microsoft Graph SDK when you mentioned graph sdks.
AFAIK, this library does not include any default authentication implementations. Instead, the user will want to authenticate with the library of their choice, or against the OAuth endpoint directly, and built-in DelegateAuthenticationProvider class to authenticate each request.
And if you were authenticating Azure AD with Active Directory Authentication Library, you can use the default token cache which use memory to store the cache or you can implement the token cache based on your requirement.
So I need to know how I can get the refresh token from the Token Cache so we can reuse it at a later stage. (yes I'm aware that it will expire after 6 months which is acceptable) .
When you using the ADAL library, there is no need to get the refresh token manually, it will handle for us to renew the access token if the refresh token is existed.
When i have the refresh token how do initiate a call to refresh the token
If you want to perform the request yourself to refresh the access token, you can refer the request below, and more detail you can refer this document.
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
OK so the answer is taking the tokencache from the PublicIdentityApp and serializing as below.
var tokenCache = _app.UserTokenCache;
var tokenBytes = tokenCache.Serialize();
var tokenString = Convert.ToBase64String(tokenBytes);
And deserializing it later.
_app = new Microsoft.Identity.Client.PublicClientApplication(ClientID);
var array = Convert.FromBase64String(bytestring);
_app.UserTokenCache.Deserialize(array);
authHelper = new AuthenticationHelper(_app);
var authorise = await authHelper.GetTokenForUserAsync()
I am having troubles in implementing OAuth in the right way.
I use a client/API architecture (Angular for front and Node.js for back) and I would like user to sign in using Google OAuth authentication only.
Here is what I think is the right way for the moment (tell me if I misunderstood something) :
Angular open a Google popup asking user's consent.
Once the user agree, Google Authorization server sends back to angular a verification code.
This verification code is forwarded to an API endpoint.
Then, the API asks Google Authorization server to exchange this code for an access_token, an id_token and a refresh_token.
Google sends those 3 tokens.
The API uses access_token to retrieve user from Google API
The API persists the user
Here is the little dillema, in my opinion, the access_token and refresh_token should be stored into the database and the id_token should be sent back to Angular client.
This way, it would allow the API to ask for resource in Google API and if the token expires it can still ask for a new token thanks to the refresh_token.
Client-side, the id_token is embedded in all requests thus allowing the API to identify the client and verify his authentication with Google certs from https://www.googleapis.com/oauth2/v3/certs.
Supposing this is right way to use tokens, how could I deal with id_token expiration since client does not have any refresh token ?
Thanks !
I do it slightly different (I have the same basic architecture though).
Angular decides the user needs to log in and displays a login popup.
The url in the login popup is not serviced by angular, but is instead directly run off of the backend server: /auth/google . (I use hapijs and bell, personally).
/auth/google is serviced by a bell plugin and initiates the OAUTH dance.
the end of the OAUTH dance results in my node server generating a local token (I just generate random bytes and store them in redis mapped to user ids)
because the initial login popup was created by window.open, the success page (generated on the api side rather than in angular) can use window.opener.postMessage to communicate the token back to the angular runtime.
This way, all my sensitive google credentials (the user's oauth token, refresh token if needed, and my application's api ID and secret) are only on the server, except for during the OAUTH dance relay when they're in a URL string during the client redirects. This is reasonably secure.
Then for all the actual user interactions with the api, I use the token I generated in step four to authenticate. This could be a JWT if you wanted, but I don't do it that way; I just use redis to map from 'longrandostring' -> userId. That lets me (for example) force everyone to re-login if I wipe the redis database that has all the tokens stored, or I can write a lua script to delete all the entries that map to a certain userid.
If you need a refresh token, you can set access_type=offline in the initial request to oauth2/auth, and you'll get a refresh token as part of the response, unless you've previously gotten a refresh token. You can then persist it on the server side and get new access tokens as needed. If you set approval_prompt=force as well, you'll force a new consent screen and be guaranteed a refresh token (but after some small number of refresh tokens granted to a user, older ones expire on the same application so it's best to only request them if really needed).
I'm using JWT for authentication in my Angular.js application, with Express.js on the server side.
Basically, when user logs in, a new token is created (using https://github.com/auth0/node-jsonwebtoken) and send back to the client. If token is valid also on the client side (angular.js part, using https://github.com/auth0/angular-jwt), a new user is created and the token gets stored in a cookie.
So, each request to certain path on the server is protected by a token validation. However, my token has an expiration time. Now let's say for the sake of argument that expiration time is 30 seconds; user can actively use my application for 30 seconds and after that, he gets logged out. That's not exactly user friendly.
So what I did was that with each request to the server, I create a NEW token and send it back in the head of response. When I receive the response in my Angular.js client-side, I read the token and overwrite the token in the cookie. That way, as long as client is active (or rather, makes requests to the server side), the token gets refreshed.
Now I'd like to know the following:
Is such an approach correct? The downside is, that token gets created at each request and send back in each head of response. Cookies get overwritten quite often (performance issues?)
What would be the correct approach?
Is it OK that the token expires if there are no requests to the server? Client might still be using the application, however, if he's only writing on client side something (or reading), the token does not get refreshed.
Thanks for your time and responses!
Yes, that is a valid approach. It is the same approach many take,
including the popular Angular module ng-token-auth. You might
consider saving the tokens to local storage, with a fall back to
cookie storage if the browser doesn't support it (see
http://caniuse.com/#feat=namevalue-storage for coverage).
I would do what you describe.
One solution is to use $interval to basically ping the API. All you need to do is send in a token a get a new one back (i.e., in headers like you are now). Keep track of how many "pings" you've sent. You can reset the number of "pings" upon certain actions like on ui-router's $stateChangeSuccess (i.e., navigating to a new view) or anything you like, including submitting a form or other non-ping requests. When the number of "pings" reaches your threshold, warn the user that their session is expiring, and after a delay, erase the stored token and log them out. Check your ping responses for authentication errors from the API, indicating that the user might need to be logged out and/or redirected.
Perhaps you just gave 30 seconds as an example token lifespan. I would recommend getting closer to the browsing session timeout that you want. As points of reference, consider that the Ruby gem devise_token_auth defaults to 2 weeks and that .NET defaults to 10 hours. Your needs may vary.
The problem is also addressed by using refresh tokens. Your access token has a short life and is verified by signature. The refresh token has a longer life and is used to get new access tokens.
When the refresh token is used to get a new access token, that is a good time to do extra checks: has the refresh token been revoked? Is this user account still valid?
Both tokens can be stored in secure cookies and supplied on every request. Doing this allows your server to transparently use the refresh token when needed and set new access tokens in cookie responses.
This is the approach we've taken for Express-Stormpath and is documented in our Authentication section of the documentation. If you'd like to offload your authentication layer, I'd suggest Stormpath. (Disclaimer: I work there, and wrote that module).
My context:
An AngularJS application using the Javascript Facebook SDK, and my distinct server (REST APIs).
Workflow:
User is logged in the client through the FB SDK using the method FB.login(callback).
This later gives a short-lived token that is then sent to the server in order to transform it to a long-lived token.
I'm interested in the mechanism of refreshing the long-lived token after 60 days.
So, reading the doc, we found this:
Even the long-lived access token will eventually expire. At any point,
you can generate a new long-lived token by sending the person back to
the login flow used by your web app - note that the person will not
actually need to login again, they have already authorized your app,
so they will immediately redirect back to your app from the login flow
with a refreshed token - how this appears to the person will vary
based on the type of login flow that you are using, for example if you
are using the JavaScript SDK, this will take place in the background,
if you are using a server-side flow, the browser will quickly redirect
to the Login Dialog and then automatically and immediately back to
your app again.
If I interpret it well, when user is ALREADY logged in through FB.login(callback), a simple redirect to the Angular Application's login flow would allow to get a new short-lived token.
I imagine that the FB.login is immediately run anew in this case, without user interaction, as written.
I want to test it simply, so what I've done is:
Logged in into the application through FB.login(callback).
Clicked on a dummy link making a simple redirect with: window.location.replace('/');
My application being a single page application, every URL should be considered as the authentication page.
But the FB.login isn't run in the background, as I expected from the doc.
What would be the reason?
Does it work only when the domain making the redirect is distinct from the client? (I just can't test this case right now)
Did I misinterpret the doc?