auth-js icon indicating copy to clipboard operation
auth-js copied to clipboard

verifyOTP response causes session to not be persisted, auto-refresh not to be triggered, & user to not be set correctly

Open jaredramirez opened this issue 4 years ago • 3 comments

Bug report

Describe the bug

When you verify an OTP, the session is not persisted to localStorage, auto-refresh is not started, and the user is undefined.

I believe this is because the return payload of verifyMobileOPT is:

 {
  "access_token": "...",
  "expires_in": ...,
  "refresh_token": "...",
  "token_type": "bearer"
}

Note that this is does not include expires_at and user.

If we then look at the definition of _saveSession we can see why:

  private _saveSession(session: Session) {
    this.currentSession = session
    this.currentUser = session.user

    const expiresAt = session.expires_at
    if (expiresAt) {
      const timeNow = Math.round(Date.now() / 1000)
      const expiresIn = expiresAt - timeNow
      const refreshDurationBeforeExpires = expiresIn > 60 ? 60 : 0.5
      this._startAutoRefreshToken((expiresIn - refreshDurationBeforeExpires) * 1000)
    }

    // Do we need any extra check before persist session
    // access_token or user ?
    if (this.persistSession && session.expires_at) {
      this._persistSession(this.currentSession)
    }
  }

A couple things here:

  1. Because session.user is null currentUser is set to be null
  2. Without expires_at the auto-refresh system is never started
  3. Without expires_at, the session is not persisted

To Reproduce

  1. Sign in via OTP
  2. See that the response does not include expires_at and user is undefined
  3. Refresh the page
  4. Session is not persisted/recovered

Expected behavior

I expect the session signing in via verifyOTP to work the same as signing in via magic link & password

Screenshots

System information

  • OS: MacOS
  • Version of supabase-js: 1.21.0
  • Version of Node.js: 14.15.5

Additional context

jaredramirez avatar Jul 29 '21 19:07 jaredramirez

I was able to work around this by

  1. Verifying the OTP
  2. Fetch the user via api.getUser
  3. Calculate expires_at from current_time & expires_in
  4. Create a new session based on the return of verifyOTP and steps 2 & 3
  5. Manually call both _saveSession(newSession) and _notifyAllSubscribers('SIGNED_IN')

This is not ideal as it relies on calling "private" functions, but it gets everything to work

jaredramirez avatar Jul 29 '21 20:07 jaredramirez

I was able to work around this by

  1. Verifying the OTP
  2. Fetch the user via api.getUser
  3. Calculate expires_at from current_time & expires_in
  4. Create a new session based on the return of verifyOTP and steps 2 & 3
  5. Manually call both _saveSession(newSession) and _notifyAllSubscribers('SIGNED_IN')

This is not ideal as it relies on calling "private" functions, but it gets everything to work

@jaredramirez thanks for providing these steps! Worked for me as well.

w3b6x9 avatar Aug 06 '21 05:08 w3b6x9

I'm guessing this issue is also related to https://github.com/supabase/gotrue/issues/141

dshukertjr avatar Aug 14 '21 00:08 dshukertjr

Hey @jaredramirez and @dshukertjr, this issue should have been fixed sometime ago already! See here

Feel free to reopen this if it's still a problem!

kangmingtay avatar Sep 30 '22 06:09 kangmingtay