Authentication Backend workflows - dfernandezm/moneycol GitHub Wiki

These workflows have been implemented in GraphQL server for v1. They wrap Firebase Auth client and admin library for the login with password functionality.

GraphQL mutations

There 3 public mutations implemented in GraphQL

  • loginWithEmail(username, password)
  • verifyToken(token: string, refresh: boolean)
  • logout(token: string)

Examples

mutation login($email: String!, $password: String!) {
  loginWithEmail(email: $email, password: $password) {
    email
    token
    userId
  }
}
---
{
  "email": "[email protected]",
  "password": "xxxx"
}
mutation verifyToken($token: String!) {
  verifyToken(token: $token, refresh: true) {
    userId
    email
    token
  }
}
---

{
  "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZjMmM4YmIyNmE3OGM0M2JkODYzNzA1YjNkNzky..."
}
mutation logout($token: String!) {
  logout(token: $token) {
    result
  }
}
---
{
  "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZjMmM4YmIyNmE3OGM0M2JkODYzNzA1YjNkNzky..."
}

Login a user with email and password

This corresponds to the loginWithEmail mutation.

  • Frontend collects email/pass and sends request to GQL
  • Server logs the user in using firebase auth
  • on success
    • stores/overrides a session in Firestore
      • current valid token is stored
      • the refresh token for this user is stored
      • lastLogin
      • email
      • userId
    • returns back email, token, userId (authResult)
    • frontend stores the token in local storage
    • frontend sends the token with every GQL request
  • On error
    • authentication error is thrown (401), user should relogin

Token verification

Verify mutation with refresh (validateToken).

  • The frontend presents an stored token to renew a long lived session and avoid re-login
  • First check if the presented token has been programmatically revoked (logged out)
    • This means the user explicitly logged out, so this token cannot be reused. It is being presented from an old session or it has been leaked
    • if token revoked, an error in sent asking to login again
    • if not revoked, continue
  • Try to validate the token
    • if non-expired token: it is verified using Firebase Auth
      • on success
      • if refresh has been requested
        • it finds the refreshToken from the user session in Firestore
        • uses Firebase Auth API to exchange refreshToken with idToken
        • stores the new data in the user session
        • returns success back
        • onError: user must re-login
      • if refresh has not been requested
        • overrides the session of this user in Firestore with data from the decoded token (it’s the same) and last Login
    • if expired token:
      • should check the expiration date in the token against the last login in user session stored in Firebase (not implemented in v1)
        • if no user session is stored in Firestore
          • fail with 401, user should re-login
        • if user session is present in Firestore
          • find the refresh token from it, exchange it with an idToken using Firebase Auth REST API
          • store the data back in Firestore
          • return success

Logout

Logout mutation.

  • The frontend sends a logout request providing a token
  • The token must be valid, otherwise the logout is rejected (401)
  • User Id and email is decoded from the token
  • The refreshToken (fetched from Firestore session) is revoked using Firebase Auth API (no more ID tokens can be issued with it)
  • The current idToken is locked out by storing it in Firestore collection ‘logged_out_tokens'
  • The user session is deleted from Firestore
  • signOut is called on Firebase Auth

References