Report expired access token - actions-on-google

I'm working to implement Google Actions, and I've came into this problem.
After successful authentication (Account Linking with OAuth) everything works fine, all of the intents (SYNC,QUERY ec...) are working.
During the test fase I've restarted the server that handles the authentication and the intents (which also holds user sessions our side) so the user session that Google has became invalid (in existent) at our side, so when a new intent is incoming with the access token (that we could say has been expired on my side) the intent fails for authentication error. And here comes the issue:
I've tried to respond with authExpired or even authFailure as described here: https://developers.google.com/actions/smarthome/develop/process-intents#error-responses
but it simply does not work. It seems like until the token does not expire on Google side, I'm not able to make it expire "intentionally". So to make it work we are forced to unlink the action or wait the expiration time than everything works as expected.
It this an intended behavior?
I hope my question was clear, if not I'm here to add more details.
Thanks,

It seems like until the token does not expire on Google side, I'm not able to make it expire "intentionally".
You are correct that this is the current behavior. Generally speaking, we expect developers to use short-lived access tokens where the expiration time is meaningful in requiring those tokens to be granted again.
Developers wishing to enable users to intentionally revoke access (outside of unlinking their account) should invalidate the refresh token provided to Google and continue to return an authFailure when those credentials are presented.

Related

oAuth Silent authentication vs refresh token and http only cookie

Somehow implementing stateless authentication always brings me headaches.
This time it concerns silent auth vs refresh tokens.
Using refresh tokens seems discouraged, however there are certain arguments I don't really get.
If you use an http only cookie to store your refresh token, what exactly is the danger?
Attackers cannot get access the cookie with Javascript and if you use SSL (which you should), I really don't understand the problem.
The resources I read always say "you should not store sensitive data in the client". Seems like an automatic, but that is implicitly impossible if you want to eliminate the need for server session state. Neither do I really understand why, since no resource ever explains how it would be cracked (and I really wonder if anybody really knows).
The reason why I have this question is because using a refresh token offers me more than just authentication.
If a user for example loses his / her device, removing the refresh token will just invalidate all access tokens over all devices (not only browser), which seems like something a user wants to do.
After all, it makes sense that when you lose a device, you need to take action to protect your data.
So the argument "if the attacker gets access to the refresh token, he can infinitely refresh your token" sounds like another argument I don't get. The attacker should not get the refresh token. How would he ever get it? It's the same as saying "if the attacker gets hold of the code of your bank card, he has infinite access to you money". Well if you lose your bank card, you call card stop; likewise if you lose your refresh token, you would delete it to invalidate all access tokens. So how is this an argument?
Can you clarify why I cannot just store my refresh token in an http-only cookie, and how a silent authentication flow improves on this?
Edit:
Note that I read a few other articles that advise to store jwt in the browser by sending the encrypted jwt signature in an http-only cookie. These articles received a lot of upvotes, so that is suddenly okay. It makes zero sense to me.
Edit on comment:
The architecture is very simple:
React / Redux SPA with REST api in the backend
Need for social login through Google, LinkedIn, Github
Need to refresh the token without needed user interaction
Access my own api resources (preferably with jwt)
Ability to revoke refresh token
I don't know why it seems complex (lol).
Refresh tokens are widely used in:
Server side web apps, where they are stored in an HTTP only cookie, as you suggest
Desktop and mobile apps, where they can also be stored in OS secure storage
Refresh tokens should not be infinitely renewable and often represent the user session time - eg:
Refresh token / User session lifetime = 12 hours
Access token / API message credential lifetime = 60 mins
The concern for SPAs in the above article is that there is no real secure storage in the browser - though you are not intending to use browser storage - so no problems there.
One risk is that users can maybe get the secure cookie and replay it to an API via browser developer tools:
To mitigate this it is of course important to ensure that APIs have well engineered authorization - and that what the user can do with a token matches what they can do in the UI.
Another risk is CSRF where a malicious app in another browser tab sends the same cookie to your back end. So you'll need to protect against this.
Note that SPAs have their own token renewal solution based on Authorization Server cookies - I would prefer that option if using an SPA, rather than issuing your own cookie.

Actions on Google - Account Linking process hits Token URL before Authorize URL?

We are trying to support the 'traditional' Account Linking flow as it seems the most general purpose, gives us a chance to surface T&C's, and we thought would be most bedded in.
But testing in the Assistant mobile app for starters, it fails for most users in our Actions app in Dev - After the user sees the Google-driven pop-up in the Assistant app with the "LINK ACCOUNTS" option - They tap that option, and our authorization screen does not appear.
Actions support have had a look at our Account Linking config and can't see any problems.
A couple of test users with newer Android phones DO see our Authorization screen, but the majority do not.
If we test the Authorization URL by pasting into a browser on the same device - It always displays just fine.
What is strange - If we look in our web server logs during the failed cases, the only hits we are seeing are to our 'TOKEN URL', whereas my understanding is a newly linking user should hit our 'Authorization URL' before ever hitting Token.
The successful cases DO hit our Authorization URL first, as expected.
Feel free to pipe up if anyone can answer ANY of the following:
Any ideas what could be causing problems here?
Or ways we might investigate deeper?
Does an app need to be in Alpha testing, or anything like that before Account Linking works?
Is it normal/expected to hit the Token URL for a user that has never successfully linked accounts?
Can anyone confirm what the Token fetch response should be in that case? (Maybe we are not responding in a way that satisfies the other end)
Does anyone have a dummy/HelloWorld Account Linking web end-point we could test against? (Geeze that would be handy for the developer community!)
I don't know exactly what is going on, but there are a couple of hints about what is happening and what avenue to investigate. I'm going to assume you're doing Account Linking with OAuth only. If you are doing a combination of "Google Sign In for Assistant and OAuth", that might change some things. To address some of your questions:
What could cause the Assistant to go to the Token Endpoint instead of the Auth endpoint?
It wouldn't go to the Token Endpoint unless it already had a Token. I could think of a few possible scenarios:
If it was going to Auth, getting a token since it was already authorized, so no window would pop up. (But you indicated it isn't going to that page.)
If the account in question is already authorized to the project via some other means. You can check https://myaccount.google.com/permissions to see if it is already authorized.
If you had tested it with this account previously and it has a token from then. If so, it should be listed at https://myaccount.google.com/permissions. Probably.
If you're not using the account you think you're using on the device in question.
How to investigate this?
Once you double-check some of the more obvious things (using the right account?):
Look at what is being sent to the Token endpoint
Does the token look familiar? Is it the same between calls? Same between different accounts?
Do you log tokens being issued? Can you?
What about the other information sent along with the token such as the client_id and client_secret?
Does it need to be in Alpha?
I'm not sure. Last I checked, it did not. I do think that it no longer works in the simulator, which is annoying, but doesn't require being in Alpha.
It does make it a little more difficult to check, however, since there is no Directory page that can tell you if the account is already linked. You'll need to go to the list of linked apps for the account to remove your app if it is: https://myaccount.google.com/permissions
Is this normal?
I wouldn't think so. It shouldn't hit the Token Endpoint unless it has an auth code or refresh token to exchange. It has to have that code/token from somewhere.
How should you respond?
If you get an auth code or refresh token that is invalid, or any of the other information provided at the token endpoint doesn't match what it should, you must return HTTP error code 400 "Bad Request" and include as the body the JSON
{"error": "invalid_grant"}
This should force it to go through reauth with the user.
Is there a public test server?
Auth0 isn't exactly public, but is free for basic use, and well suited for test purposes.

JWT logout feature without using blacklist?

I have used JWT before, but they were API that didn't need logout feature.
I need to implement logout feature for a API of an android app and SPA. When I looked it up I found that there are two ways to do it.
the easiest way is to delete the JWT Token from client side and call it a day.
The logic behind this is that since no session of any kind is maintained in server deleting the token in client side should be enough.
But it still leaves the possibility that, if the token falls in wrong hands they can still use it even after the user is no longer using the token.
Given if the app is well designed and uses HTTPS then chances of this happening is very low and can be minimized by keeping the valid time for the token short. But in my case the tokens are valid for 30 days.
the second option is to maintain a blacklist of tokens in server side
This solves the problem of the token still being usable even after user has logged out and stopped using it.
But it adds a complication of needing to run a cronjob to remove expired token form the blacklist table. Otherwise the table will eventually become ridiculously large.
It also kinda defeats the point of using JWT. Maintaining blacklist is very similar to maintaining session. We have to run an additional db query for every request. And it scales badly, as the no. of users grows the no. of token that needs to be blacklisted will also grow (this will be a bigger problem for API like mine with multiple front end apps and long validity period for the tokens).
Then I got an idea for third way.
Add jwt_secret row in user table that stores randomly generated string. Use it to sign the JWT Token then on every request use user id in the jwt payload to get the user form db(which is not an extra query, we have to do this anyway) and validate the token signature using jwt_secret of the user. When the user logs out we change the jwt_secret which makes all token out there useless.
At first I thought this was a great solution only to realize that in this setup if user logs out of one device or browser he/she gets logged out of all devices.
So is there a another option? Or a way to modify any of above approach to solve the problem. Or am I over thinking this and one of the above option should be used?
For logging out, which as you pointed out is a user initiated action, I don't think you need to do anything extra. If the user somehow did not delete his JWT, then so be it. He wouldn't be getting any extra access over to what he is already entitled.
However, your question seems to hint on the problem of how to know that a JWT is valid. Again, as you pointed out, if a JWT somehow fell into the wrong hands, then there may be no avoiding this. But, with each request you would typically be doing several types of validation against that JWT, e.g.
checking the claims of the JWT, such as the token expiry date
assuming the claims pass, then checking that user's ID against your database table to make sure the account is active, has not been suspended, etc.
My point here is that if you need to keep track on the server side that a logout has happened, you might need to persist this to a database. But, I don't think you would need this.

Azure AD OAuth Refreshing Tokens

I'm making an application that among it's task will use the REST API in KeyVault. I already have functions written that will query the KeyVault for the secret without an issue.
I also have functions written to request an OAuth token from AAD, following the documentation on this link:
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
What I'm not sure about is; Since the application is going to be installed on hundreds of computers when a token expires and the function to refresh the token is called chances are that more than one PC is going to make the POST. What is the best practice for a scenario like this? Should i just configure an exponential back off after a refresh token function is called?
The app installed on the machines will not have the ability to talk to each other.
The only way I can think to do this is to use a logic app as the broker but that would defeat the purpose of the KeyVault.
The document you provided is using the code grant flow to acquire the access token. This flow requires users to login to acquire the token. And did you mean all the PC you installed will use the same account to acquire the token?
If yes, you can design you own token cache. For example, you can using an SQL server to store the cache. Then the app will search the token/refresh token in the token cache before it sends the token request. And if the token is expired, you can refresh it. In this scenario, all PC will share the same access token since they are sign-in with same account.
If not, you need to refresh for the every PC when the access token is expired. Because the access token is different from each user.
So after some testing and verifying with MS it looks like the documentation on the link is outdated. When a token is generated it has a lifetime of 8 hours (this is configurable) so every time I make a request to /token a new token is handed out, since the time window is small I don't need to worry about token refreshes since PCs won't be on for over 8 hours.
The other part of this is that i built a function to test the validity of the existing token, before i query any azure service i test the token validity, if it fails a new token is requested. Since the token lifetime windows are short and each machine gets it's own token (i thought all machines were getting the same token, code error on my part) this is a non-issue anymore

Google oAuth2 tokens invalidated more and more

I have a web app built on oAuth2 that has been in production for 5+ years. Users Authenticate and Authorize with Google and grant my application access to the Google Analytics data.
All of a sudden I am seeing a surge in failures when refreshing my users oAuth2 tokens. This is the call:
https://accounts.google.com/o/oauth2/token
Passing these parameters:
client_id=xxyyzz
client_secret=xxyyzz
grant_type=refresh_token
refresh_token=xxyyzz
This seems to be be on accounts that are less active (i.e. it could be 15+ days between instances where we make calls on their behalf). I have to reach out to them and have them "ReAuthorize" against Google to get things working.
1) Did something recently change with Google oAuth2 or the GA Core Reporting API?
2) If access tokens are not refreshed after some time period will my refresh token become invalid? i.e. should I make calls against all accounts even thought I don't need the data; just to keep the refresh token from going stale?
Thanks,
Mark.
Update on Scope
It was requested to provide the scopes in play here:
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/analytics.readonly
11/17/2016 Update:
We did find an issue that resulted in some tokens being purged. We are working on to make sure it doesn't happen again. Unfortunately there is no way to restore the tokens that were deleted and your users will have to reauthorize again.
11/11/2016 update:
We are actively investigating the issue. You should ask your users to re-authorize the application.
(from Google Identity/Auth team) We would like to investigate this a bit more to make sure our system is working as intended. Other than the token revocation (with certain scopes) on password change, we haven't changed the token revocation policy.
Would you please ping me via my G+ profile?