How do you keep a user logged in for more than 24. hours?

I’ve been putting this off for a while. But both me and my users are getting a bit frustrated of having to log in every single day you visit the website.

I remember back when I was figuring out how to just get a custom signup/login working. The default token expires after 12 hours or something like that.

I believe I was told that there was a “way” to extend that, but it was never explained.

Does anyone know how to extend the tokens so I can keep my users logged in for e.g. 30 days at a time?

Use the refreshToken to refresh the user idToken.

mutation {
  userRefreshToken(data: {
    email: ""
    refreshToken: ""
    authProfileId: ""
  }) {
    idToken
    refreshToken
  }
}

You can keep doing this for up to 7-days.

@sebastian.scholl thanks,

This call seems to work fine when testing it before the token becomes invalid.

However waiting 24 hours to test if it works while it’s invalid is a chore, but doable.
But waiting 7 days to see what happens when the refreshTokens stop working is… not fun. Especially if I’m doing something wrong and I need to start over with a new 7 days wait.

Is there any way to invalidate an authToken and refreshToken the same way it would automatically be invalidated by the system? So I could test the different cases?

Thanks,
Mark

Hey Mark - sorry but I don’t understand the second part about invalidating the token.

The refresh token is valid for up to 3 days. If you handle the Token Expired error and run the refreshToken mutation, then you’ll either get back a fresh token or know that the refreshToken was also invalid and have to prompt your user to sign back in.

@sebastian.scholl

Didn’t you say. 7 days? “You can keep doing this for up to 7-days.”

What I don’t have is a way to test it. I wrote some code, but I have no idea what the GraphQL response will be when the refreshToken is no longer valid, cause I haven’t been refreshing. the token for 3? (or hopefully 7 days) before it stops working.

Which means I can’t deploy my code, cause I don’t know with a 100% certainty that it will work.

and I don’t want all my users to not be able to login anymore (without clearing their cache) after 3 / 7 days.

I think I’ve covered the edge-cases required, but without knowing what the response will be when refreshToken stops working, I can’t test it.

It also takes me 12 or 24 hours? to test the case when idToken stops working to make sure it can refresh it correctly.

Here’s the logic I have to figure out if I should send the user to the login page.

const { loading, error, data, refetch } = useQuery(CURRENT_USER_QUERY, { fetchPolicy: 'cache-and-network' })
  const [refreshToken, { loading: refreshTokenLoading, data: refreshTokenData, called }] = useMutation(REFRESH_TOKEN)

  // is fetching user or refreshing token
  let authenticating = loading || refreshTokenLoading
  const isLoginPage = Router.router.route.includes('/dashboard/login')

  useEffect(() => {
    // The user has no authToken saved in storage or window sess -> make user login
    if (hasStorage && !localStorage.getItem('authToken')) {
      if (isBrowser && !window.authToken) {
        console.log('useEffect - dashboard push')
        Router.push('/dashboard/login')
        return
      }
    }
  }, [])

  if (error && !isLoginPage) {
    // if there is an error - make the user login again and remove tokens
    removeStoredTokens()
    console.log('onError loginPush')
    Router.push('/dashboard/login')
  }

  // if authToken is saved, but expired user.id will be null
  if (data && data.user && data.user.id === null) {
    // if refreshToken hasn't been attempted, try refreshing.
    if (hasStorage && localStorage.refreshToken && !called) {
      console.log('refreshToken - start')
      refreshToken({ variables: { refreshToken: localStorage.refreshToken, authProfileId: AUTH_PROFILE_ID } })
    } else {
      // if refreshToken has been attempted and got a valid response
      if (refreshTokenData && refreshTokenData.userRefreshToken) {
        console.log('refreshToken - success')
        storeTokens(refreshTokenData.userRefreshToken.idToken, refreshTokenData.userRefreshToken.refreshToken)
        // refetch CURRENT_USER
        refetch()
      } else if (!authenticating) {
        console.log('refreshToken - failed')
        // if no auth requests are in progress and refreshToken data is invalid -> make user login
        removeStoredTokens()
        Router.push('/dashboard/login')
      }
    }
  }

I need to test the following scenarios:

valid idToken & valid refreshToken: :white_check_mark:
expired idToken & valid refreshToken: :stop_sign:
expired idToken & expired refreshToken: :stop_sign:

Right now I can only test the first case. I have no way to test the second and third case without being able to invalidate (expire) my tokens. And there’s no docs that tells me what the response will be when it happens.

A refresh token is valid for 3-days, you can keep refreshing a session for up to 7 days.

Yes you do:

Query

mutation {
  userRefreshToken(data: {
    email: "user@email.com"
    refreshToken: "THIS_DOESNT_LOOK_VALID"
    authProfileId: "ck5pyomad003g07ml2sv88ot6"
  }) {
    idToken
    refreshToken
  }
}

Response

{
  "errors": [
    {
      "code": "TokenExpiredError",
      "message": "Token expired",
      "details": {
        "token": "jwt expired"
      }
    }
  ]
}
1 Like

Thank you! that helps a lot!

1 Like

For sure, @MarkLyck !

1 Like