Rails deployments resulting in spikes of "Can't verify CSRF token authenticity" - ruby-on-rails

This is a Rails 5.1 web app migrated from a Rails 4 app (in turn migrated from a Rails 3 app) deployed to Datica (which is Docker based).
After each deployment, our logs record spikes in the occurrence of "Can't verify CSRF token authenticity" warnings and corresponding 401 statuses. The front-end is a React app, with most client-server communication happening over XHR, so some people receive 401 multiple times. Refreshing the browser has solved the 401 status for me twice, so I think the fall-off in the spikes indicates people refreshing or ceasing to use the app because it isn't working for them (see screenshot of the log graph showing the spikes).
The app uses cookies for session storage. The CSRF token is in the body of the page when it was first loaded. What I have observed would be explained by the cookies being given a new CSRF token, so that there is a mismatch between the CSRF token in the body of the page and that in the session, but I do not understand what would cause the server to issue a new CSRF token after a deployment.
Thinking this might be due to a delay in the newly launched instances receiving the Origin header, or the old instances ceasing to receive it, I set config.action_controller.forgery_protection_origin_check = false in application.rb. However, there were spikes after deploying last night and again this morning (and it wouldn't really make sense anyway since refreshing the browser appears to solve the problem).
Any ideas as to how a deployment would cause the server to issue new CSRF tokens to sessions? Or any other ideas or other hypotheses?
Thank you!

The problem was that MyApp::Application.config.secret_key_base was never set. Back when the app was migrated from Rails 3 to 4, the recommendation was to wait until the user base was completely on 4 before uncommenting that line. But that never happened.
I presume that if that secret_key_base isn't set, it automatically generates an in-memory key base for generating CSRF tokens, resulting in a new key base every deployment.

Related

Google Calendar API v3 - Persistent Authorization with Code

Im wondering if anyone has any answers to this. If one follows the quickstart here:
https://developers.google.com/calendar/api/quickstart/go
we can get authorization from a user that allows us to do things with their calendar.
It seems the HTTP Client given back from the config handles calling the refresh token and keeping the client up to date.
First, as a side-question, does anyone know how long this is allowed to persist? I read in a doc somewhere that for unpublished apps/projects its 7 days, but it didn't specify a timeline otherwise. Is it indefinite or will this expire at some point (ie the refresh token runs out after 30 days). And is this avoidable at all?
now, the real question - if you take the service down entirely, ie for an update, and restart it, is there any way to opick up the authorization again? In the tutorial its writing a code to disk and reading as needed. In my case I just hold reference to the things I need in the application, so obviously when the service went down id have to reauthorize. I then tried writing the code to disk on a persistent volume and re-reading from that, but it doesnt get authorized - I guess because the new instance of the service has a new instance of the oauth config, and it wont accept the old code perhaps?
In any case, im wondering if anyone knows of a way to make this persist through ssytem restarts, or if the only real option here is to move the calendar service client to a small microservice on the side that we do not restart, and contact it from elsewhere as needed.
Thanks in advance!
The refresh token expiration is documented here. As you've noted, tokens expire in 7 days for projects in "Testing" status. Refresh tokens for projects in production last indefinitely, but there are some scenarios where they may get invalidated (user revokes access, token has not been used in 6 months, the account has over 50 live tokens, etc.). It's not mentioned but if you change your OAuth scopes you'll probably need to reauthorize as well.
This means that as long as you keep your refresh tokens and none of the invalidation conditions are met, you should be able to keep using them to get new access tokens even if your service goes down temporarily. But as mentioned in the documentation, you should anticipate the possibility that the token stops working and redirect the user to authorize again.
My guess is that in your case the refresh token stopped working for some reason (maybe the 7 days limit) and the application just tried to use the same expired token. The Quickstarts in Google's documentation usually handle the creation of the token file and how to reuse it, but they don't include the part where you have an invalid token and need to reauthorize.
References:
Google's OAuth2 Overview
OAuth2 for Web Apps

Is possible to decline all old access tokens?

I am developing an android mobile client and signing with oauth2 to our server that is written in c#. Everything is working well, until the server is rebooting.
I'm crashing every call to the server.. at first I've thought that my access token is not valid anymore. but after I've decided to have my own local server I saw that my calls do reach the server and they crash inside because of some static lists of tokens and user data that the server team developed and obviously getting cleared after restarting the server.
I've told them to recreate their lists of data and access tokens, but no luck for me there..
My question,
I'm not so good in server-side and oauth2 developing but i'm pretty sure there is a solution for what i want. I've tried searching for few hours without success. My thought is - To make the server decline all old access tokens from previous run of the server - and i will get unauthorised code in my client (Now i'm getting just crush in server that i don't know why and how to react in my app) Something like - Each time the server restart it will have a random seed and will create its access tokens with this seed.
Is there something like this ? or some other "Not so much work" solution for the lazy server-side team :)?
The service that is issuing you the OAuth token is also the service that needs to revoke tokens. There is nothing inside a token that you can change to invalidate it that would also not corrupt it.
If your server is crashing because you are sending it unknown / invalid tokens, this is a serious problem. The first step than anyone will do (should do) is to validate the token. Evidentally they are not. Security requires attention to detail and having a server crash due to tokens is a security problem (Denial of Service).

Rails CSRF Expiration Time

I've got a issue where some users that go idle on my site for a period of time receive a CSRF error when submitting post requests. I don't want to disable the security feature in Rails because of its importance, so I was thinking to display a page timeout alert instead. However I cannot find anywhere what the Rails default timeout is for the authenticity_token. Can someone please point me in the right direction?
Thanks in advance.
UPDATE
When I look at cookies for my site Chrome shows that the session cookie expires when the browsing session ends. If that's the case and the reason that I get the CSRF error is due to an expired session, how does it expire if the browser is never closed?
The default behavior is for the CSRF protection to use cookie-based sessions, and for the cookies to expire when the session expires. It sounds like the session is expiring, causing the CSRF error.

Using refresh token fails; was working before

My Box app (using v2 API) keeps track of when an access token expires, and when the app realizes the access token is about to expire, it request a new access token using the refresh token (the reason is that it simpler to avoid errors than to handle them).
I noticed that lately (this definitely was working properly a few months ago), when my app starts up (after more than 1 hour of non-use), the request for a new access token fails! The interesting thing is that at this time, my app has not attempted to use the now expired access token.
Should my app first do a dummy action with the expired access token maybe as a workaround? Again, all this was working as expected when I converted the app over to V2 API. At that time, the refresh token was valid for 14 days.
Thanks
Peter
I've tried to reproduce it, and I'm not able to. My refresh tokens are all working. It could be that you are getting an error condition on your refresh that you are not catching. There are some cases where your admin can decide that the app you are using is no longer approved for your enterprise, and on refresh, you'll be booted out. Or you may have mis-typed your password enough times that your password is going into "captcha" mode, looking to verify that there's a human, and not a machine on the other end of the wire.
Let me suggest that you log out of the app, and log back in. You're more likely to get presented with the error, since Box will be giving you the auth screen, and Box handles all the weird cases in their OAuth2 screens.
Yet another reason, that for all the pain of implementing Oauth2, it's worth it to get a better experience for your users.

What causes intermittent Invalid Grant

I'm getting the following
{
"error" : "invalid_grant"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:103)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:303)
at com.google.api.client.googleapis.auth.oauth2.GoogleRefreshTokenRequest.execute(GoogleRefreshTokenRequest.java:130)
This only happens in my production Appengine instance, (ie. not on dev server), and it only happens for the email address that I use for testing on both dev and production.
My working hypothesis is that it is something to do with the user being granted a refresh-token on the dev server which is somehow interfering with the stored refresh-token on the prod server.
Can anybody confirm this explanation, and is there a best practice on how to deal with this exception?
Currently only the last 25 refresh tokens granted by Google work.
We basically keep a queue of size 25 of generated refresh tokens.
That mean that on your testing account if you happened to generate more than 25 refresh tokens the older ones will start to be revoked.
Maybe that is what is happening here so I wanted to point this out, it could be that you generated more than 25 refresh tokens on your dev server with your test account and the token that was in prod got dropped (because there are 25 newer ones).
That is something that is not documented about our authentication servers and as such be aware that it could change anytime.
In general when this exception happens you need to make the user go through a new OAuth 2.0 flow in order to get a new refresh token.

Resources