I made a appengine api that requires authentication. If I access it via web, I'm redirected to a google sigin process and then every request sends a ACSID cookie. Works flawlessly.
Now I want to use the api elsewhere. I already have a oauth2 token i got from logging in. From what I understood I should call <myapp>.appspot.com/_ah/login?auth=<oauth2token> and the request would return the cookie to pass to the future calls.
But it's returning status code 500, no matter the token I pass, and I'm reading about and starting to believe it's been deprecated. What's the proper way to do it now?
Related
I have an angular app hosted in one azure windows app service and a asp.net core api hosted in another, both are protected using the app service authentication feature. I am using an app service plan which currently has two servers. I am using the token store and it is using the file system to store the tokens.
When the angular app calls the api it needs to pass an access token in the authorization header. The access token is retrieved by performing a GET on the \.auth\me endpoint and sending the AppServiceAuthSession cookie as the credential. The returned token is then cached in session storage and used for subsequent requests until the token expires. When the token expires I call the \.auth\refresh endpoint (and send the AppServiceAuthSession cookie) and then call the \.auth\me to get the refreshed token.
All this works well when running on one server but when the app service plan is scaled to 2 or more servers the call to \.auth\refresh succeeds but the subsequent call to the .auth\me endpoint gets a token which has already expired. I can tell the token has expired by checking the internal exp claim and also the call to the api fails with a 401 Unauthorized when it would normally succeed.
If I scale back to one server the problem goes away and if I enable ARR affinity the problem goes away but I don't want to have to enable affinity just to resolve this.
also the call to the api fails with a 401 Unauthorized when it would normally succeed.
You shouldn't be calling /.auth/refresh on the API app. You must call /.auth/refresh on the WEB app because the auth token is produced on the WEB app.
Alternative to the bearer token is the AppServiceAuthSession cookie from your client request to /.auth/refresh.
The returned token is then cached in session storage and used for subsequent requests until the token expires. When the token expires I call the .auth\refresh endpoint (and send the AppServiceAuthSession cookie) and then call the .auth\me to get the refreshed token.
We have a user-facing web application that calls an API backend, which in turn queries the MSFT graph, just to be sure we have the context correctly captured. At each phase, we anticipate a distinct AAD registration:
Web app registration (with permission to API app)
API app registration (with permission to Microsoft Graph)
Our initial assumption is that the user hasn't explicitly given their agreement to using the Microsoft Graph because this looked to be tied to adding the graph permission. Since the user isn't involved if you're merely updating the existing token, there isn't a chance for that consent to be obtained. The user would need to re-login with an explicit consent prompt, which could be done by calling /.auth/login/aad?prompt=consent. But we wouldn't anticipate that to cause the expiration problem. I'm speculating here, but it's possible that a cached, outdated value is being utilised in place of the permission error. There would need to be input from Connor.
The logs from the actual Authentication / Authorization layer itself, particularly if there is an error message, are another piece of information that would be useful to have. To obtain these logs:
From your app in the portal (the API app is what I'm most interested in): “Platform features” > “Diagnostic logs”. Change “Application Logging (Filesystem)” to “On” and set the level to “verbose.” Hit Save.
Back to “Platform features” > “Log stream” and keep that window open as you reproduce the issue (in this case, the call to the API app)
Actually, the issue is that AAD bearer tokens are incompatible with the /.auth/refresh API. Instead, you must use a session token (_x-zumo-auth_ header) or a session cookie (_AppServiceAuthSession_ cookie), which are the results of a login activity.
For more info - see here #refreshing-the-access-tokens
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).
Help me pick the right OAuth2 grant type for my Angular App and my REST API?
UX-wise I want just one login form on my front-end, that would ask for username/pass(no dialog asking for permissions). I think the "Resource Owner(Password) Grant" is the most appropriate for me(since I control front&backend), but I'm not sure how should I handle access token refresh.
Correct me if I wrong about the flow:
When user submits credentials through login form, access token is returned.
I can store this token in LocalStorage to make subsequent Ajax requests with it.
As I understand access tokens should be short-lived. And should be updated with Refresh token. Should the refresh token be returned with the access token after initial login and also stored on the client? If not what is the alternative?
Should there be any session maintained on the server to invoke access token refresh? or I should make calls from front-end to refresh the access token when it is about to expire. But then I need a refresh token on the front-end, right?
As you see there is a mess in my head about refresh token. Would be great to have some clarification or suggestion for another grant implementation.
Backend technology I guess is irrelevant here, but just in case it's Symfony2 with FOSOAuthServerBundle.
When you are calling the TOKEN endpoint (for every grant_type possible) on a OAuth Server, you get an access_token but other information as well (I think there are all here):
{
access_token: // your short-lived token
expires_in: // number of seconds before the access_token is invalid
token_type: // the type of the access_token
scope: // scopes of the access_token
refresh_token: // long-lived token to get a new access_token
}
You need, in my opinion, all these information (maybe the scope is unused, but all others will be used later). You have to store the access_token to ba able to make API calls. After seconds, your access_token will not work anymore. You will need to get a new one. You can either ask the user to log in AGAIN or use the refresh_token.
You will have to call the OAuth Server on the TOKEN endpoint but with a grant_type: refresh_token. You will have to provide the refresh_token from the first request (among other information) and in return you will have the same response as above. In fact, I think you will have to do that every time an access_token is expired. In my opinion, the server side does not know anything about sessions or connected users. It knows about valid and invalid access_token.
This is OAuth. If you don't want to have to refresh everytime, you can make a long-lived access_token (by setting the expires_in), I think this is the only solution that makes sens in an OAuth context.
Do you need some clarification about OAuth in general?
I am developing an app on Google AppEngine, and utilizing Google+ SignIn with server-side flow method as documented here.
I can get the token as above, and stores it in session.
However, i want to check at login, if the token is valid or has expired. How can i do that?
Note: I use Google API client libs for java.
You can call the tokeninfo API method to get info about a token, including how long before it expires (if < 0, token is expired)
https://developers.google.com/resources/api-libraries/documentation/oauth2/v2/java/latest/com/google/api/services/oauth2/model/Tokeninfo.html
In addition to Jason's answer:
You could also estimate if the token is still good by setting another session cookie with the timestamp of when you acquired the token. They expire approximately hourly (there is some variability).
Since the tokeninfo endpoint requires a request, you could also skip hitting the tokeninfo endpoint unless you have other reasons, such as needing to verify that the token matches the app and user, and just make normal requests until they you get a bad request error. When you get that attempt to refresh your token.
I've run into an issue when using OAuth 2 authorization codes in an web app's URL, such as is returned by Google's OAuth method (https://developers.google.com/accounts/docs/OAuth2Login).
I've been using the google redirect method; where you redirect the user to a Google URL, passing in client_id and redirect_uri. The user authenticates and the authorization code is passed to the redirect_uri as a
The issue is that the access code stays in the page URL, so if the user bookmarks or posts the URL, they are sending an invalid Authorization Code.
Eg:
http://myapp.com/?code=kACASDSDdAS81J5B8M_owCyUNgV46XdZaqBBMh4T8OJFEKPRrgN7gtiFOcMW5Fv3gk
What is the best way to handle this case? Ideally, I would like to send the authorization code in a POST body as it isn't visible to the player?
I've spent a bit of time looking at Google App Engine (the platform I'm using) to redirect the user, but can't seem to send a POST body in a redirect.
After the user is directed to your app with the authorization code in the URL query parameter, you should:
1) Exchange the authorization code for an access token by making a HTTPs POST to Google's OAuth 2.0 token endpoint and save that access token as appropriate (datastore, memcache, etc)
2) Redirect the user to a URL without the ?code. You can't send a POST body in a redirect (HTTP doesn't allow it), but that shouldn't be necessary if you store the access token server-side for making API calls.
If you must make the token accessible client-side, you can:
a) Send it back as a cookie along with the redirect (which exposes it to the client, though you could encrypt it) OR
b) Generate a HTML form, with JavaScript for auto-submitting it instead of doing the redirect. Kind of ugly, but common.