-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MNTOR-3353: add refresh token logic to session management #4777
Conversation
One thing I'm trying to figure out is where to add the client side of the session error to force re-sign in. |
Preview URL 🚀 : https://blurts-server-pr-4777-mgjlpikfea-uk.a.run.app |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a "How to test" section? I'm unsure how to tell now whether this works as intended.
The most important thing that I think needs changing is doing this check when constructing the JWT, rather than when validating the session, since the latter happens pretty often.
src/db/tables/subscribers.js
Outdated
*/ | ||
// Not covered by tests; mostly side-effects. See test-coverage.md#mock-heavy | ||
/* c8 ignore start */ | ||
async function updateFxATokens (subscriber, fxaAccessToken, fxaRefreshToken, sessionExpiredAt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused by the significant overlap between this function and updateFxAData
- is that one used in similar situations as this one? Should it be? It's also calling destroyOAuthToken
, should this function do that too?
Could you add some comments to the code to prevent such confusion from future readers?
const dbFxATokens = await getFxATokens(token.subscriber.id); | ||
if ( | ||
!dbFxATokens.fxa_session_expiry || | ||
dbFxATokens.fxa_session_expiry.getTime() < Date.now() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should try rotating it if it expires soon, rather than when it has already expired? Since sessions have a lifetime as well in which the token can expire.
dbFxATokens.fxa_session_expiry.getTime() < Date.now() | |
dbFxATokens.fxa_session_expiry.getTime() < (Date.now() - 5 * 60 * 1000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if we should artificially set a time (not really a best practice)
I think the point is to let sessions expire and potentially force a refresh or relogin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the question is: how do we do that? Are we going to refresh the session every time an API request to FxA fails with the relevant status code? Since this callback won't necessarily automatically get called when the session expires.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the question is: how do we do that? Are we going to refresh the session every time an API request to FxA fails with the relevant status code? Since this callback won't necessarily automatically get called when the session expires.
Yes I am wondering that too... I'm not sure what is going to trigger this session
callback if e.g. a fetch
to some API (like subscriptions details) fails.
@@ -209,7 +213,7 @@ export const authOptions: AuthOptions = { | |||
} | |||
return token; | |||
}, | |||
session({ session, token }) { | |||
async session({ session, token }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't refreshing the access token happen in the jwt
callback? As I understand it, the session callback gets called pretty often, so hitting the database there can cause pretty heavy load. And the JWT would still contain the expired access token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there are two approaches to this. The database route is a bit heavy, but it's also a bit safer. It's outlined in the next-auth doc.
We've traditionally opted for storing the sessions etc the database (prior to moving to next-auth). We were also using redis for session management. I think it should be an either-or situation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, I'm not saying not going the database route, but doing it less often? I think the session gets refreshed whenever the user switches tabs, or about every minute when the user has a tab open, at least when an app is using the JWT session strategy - which Monitor does.
We could consider switching to the database session strategy, in which case I think the session callback will be called less often and doing the refresh there makes sense, but if we don't do that, I'd be afraid we'll be hammering our DB too much. But I'm not a back-end engineer, so I'll defer to your judgment :)
Co-authored-by: Vincent <Vinnl@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like from talking this morning that you're going to investigate switching over to the database strategy - I think that will make things a lot clearer, since we're sort-of using both strategies right now.
const dbFxATokens = await getFxATokens(token.subscriber.id); | ||
if ( | ||
!dbFxATokens.fxa_session_expiry || | ||
dbFxATokens.fxa_session_expiry.getTime() < Date.now() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the question is: how do we do that? Are we going to refresh the session every time an API request to FxA fails with the relevant status code? Since this callback won't necessarily automatically get called when the session expires.
Yes I am wondering that too... I'm not sure what is going to trigger this session
callback if e.g. a fetch
to some API (like subscriptions details) fails.
@rhelmer one thing we'd want to do in stage is to load test this for database connection (we will be checking db pretty frequently with the session changes). I'm optimistic that most of it should just be |
Cleanup completed - database 'blurts-server-pr-4777' destroyed, cloud run service 'blurts-server-pr-4777' destroyed |
References:
Jira: MNTOR-3353
Description
Test
Test for refresh token
db:migration
and make sure thefxa_session_expiry
col existsTest for refresh fail
fxa_session_expiry
,fxa_access_token
, andfxa_refresh_token
columns in thesubscribers
tableChecklist (Definition of Done)