Authentication Tokens and Sessions

Turn an authentication system into a login system using authentication tokens

Authentication Tokens

Authentication Overview

  • Registration
    • User sends username and password
    • Validate password strength
    • Store bcrypt salted hash of the password
  • Authentication
    • User sends username/password
    • Retrieve the stored salt and salted hash for the username
    • Salt and hash the provided password
    • If both salted hashes are identical, the user is authenticated

Authentication

  • With authentication, we want users to be able to:
    • Access their private data
    • Make authenticated posts to the server
  • When you take these actions on a web app:
    • The app should verify that you made the request
    • Only serve your private data to you
    • Do not let anyone else make posts in your name

Authentication

  • How does the server verify that you are the one who made a specific request?
  • We only have authentication
  • Users would have to type their username and password with every single protected request
    • No! Terrible user experience
    • Some apps make authenticated requests every few seconds to load more content while users doom scroll
    • You would not use this app if you have to type your password constantly

Authentication

  • Insecure Idea: Store the username/password in cookies and send them on every request
    • Password is stored client-side in plain text
    • No! Never store passwords in plain text
      • Not even client-side! Don't do it.
      • Never trust your users, not even with their own security
    • Best case, increases attack surface area since the password is handled much more often in requests

Authentication Tokens

  • Instead of authenticating the username/password on every request:
    • Issue an authentication token
  • When a user is authenticated, generate a random authentication token
  • Store [a hash of] this token in your database and mark the username of the account that was authenticated
  • Set the token as a cookie for that user
  • Whenever a request comes with that token, treat them as the user associated with that token
    • By looking up the token in your database

Authentication Tokens

  • With authentication tokens:
    • We now have a login system! 🎉
  • As long as the user has the authentication token as their cookie, they are logged in
    • All their requests are authenticated by the server
  • You can/should set these tokens to expire
    • Expire client-side (cookie expiration)
    • Expire server-side (storing an expiration timestamp in your database and ignoring the token after that timestamp)
  • The token might expire in years, depending on your application

Authentication w/ Tokens

  • Once a token is generated, set it as a cookie
  • Now the token will be sent with all subsequent requests
  • Use the token to lookup the user
  • The possession of the token verifies that this user did authenticate in the past

Authentication w/ Tokens

  • Check each request for a cookie with a token
    • Lookup the hash of the token in the database
    • If the token is found, read the associated username
    • Proceed as though this request was made by that user
  • If the token is invalid or no cookie is set
    • Do not respect the request and return a 400-level response code:
      • 401 Unauthorized - User is not logged in
      • 403 Forbidden - User in logged in, but trying to do something that they are not allowed to do
  • Ensure all sensitive pages/features are secured this way!
    • The front end cannot be trusted (NEVER trust your users)
    • All checks must be performed server-side

Logging Out

  • When a user logs out:
    • Invalidate the token
      • This needs to done server-side
      • Remove the token from your database, or mark it as revoked
      • If you see a logged out token again, do not treat the request as authenticated
      • If a token is stolen, this allows the user to regain control of their account
    • Delete the cookie
      • Set it with an expiration date in the past, or max-age of 0
      • The browser should delete the cookie

Authentication Tokens

  • Authentication tokens need to be random and unguessable
    • The token must have enough entropy that they cannot be guessed by an attacker
    • Eg. An attacker should not be able to send requests with random tokens until one matches a logged in user
  • Generally, there should be at least 2^80 unique tokens that could be generated (80 bits of entropy)
    • More is better!
  • Since you are generating these tokens, and no human has to remember them, you can simply choose the entropy
    • Generate a random hex value of length 10?
      • You already have 160 bits of entropy
    • Why not generate length 50 and have 800 bits of entropy 🤷

Storing Authentication Tokens

  • (Caution: These tokens need to be stored on the server){.yellow}
  • These tokens are about as sensitive as passwords!
    • Stealing a token and setting a cookie with that value grants access to an account without even needing a password
  • Protection: Only store hashes of the tokens
  • Anyone with access to the database cannot hijack anyone's Sessions
  • With such high entropy, no known attacks can find the tokens given the hashes

Storing Authentication Tokens

  • Do not salt auth tokens
  • With arbitrarily high entropy, even rainbow tables are useless
    • Salting does not add any protection when attacks are already effectively impossible
  • Salting would make your job more difficult
    • You id a user based solely on their token
    • You don't know the salt for a user without looking up their account
    • You need to test all users in your database making every request O(n) where n is the number of registered users
  • brcrypt is made for passwords. Don't use it for tokens
    • SHA256 is preferred

Recall the SameSite Directive

  • SameSite
    • Determines when the cookie will be sent on 3rd party requests
    • Lax - Cookie only sent when navigating to your page -and- all 1st party requests
      • The default setting if SameSite is not set
    • Strict - The cookie is only sent on 1st party requests
      • ie. The cookie is only sent to your server when browsing your page
    • None - The cookie is always sent. Requires the Secure directive to also be set
  • Set-Cookie: id=X6kAwpgW29M; SameSite=Lax
  • Set-Cookie: id=X6kAwpgW29M; SameSite=Strict
  • Set-Cookie: id=X6kAwpgW29M; SameSite=None; Secure

SameSite Specifics

  • Auth tokens are typically lax, so we must understand the rules of when the token is sent
  • All 1st party requests contain lax cookies
    • As long as the site making the request is the same as the site that set the cookie, it will be sent
    • Here "site" means the protocol and host combination. Not the port
      • Example: A request from localhost:5000 to localhost:8080 is considered SameSite
  • A 3rd party requests contain lax cookies if it both:
    1. Is a GET request
    2. Navigates to your app
  • This is a major reason why GET requests should not change the state of your app
    • A GET request should only get information
    • Since the user is navigating to your app, an attacker cannot see the response