Skip to content

Further improve authentication #158

Description

@jbriones1

Description

Once #154 has merged we still have some features to improve authentication. We still check the database for every single authentication request, but we can remove that with JSON Web Tokens (JWTs).

Tasks

  1. Adding a JWT_SECRET key to our web server.
  2. Modifying our user_session table.
  3. Changing our hardened cookie (access token) to be a JWT that contains enough information to not require a database read.
  4. Access token will no longer be a session cookie and will expire after a long-ish time.
  5. Add a second cookie (refresh token), which expires after a short time.
  6. Add a third cookie, which is plaintext, expires after the session, and contains information about the user.
  7. Update auth endpoints.
  8. Update dependencies on other endpoints.

User Session table updates

  • Adding a scopes column to our user_session table. This means we don't need to check the officers table for who can do what every time.
    • scopes will be an array of text (TEXT[]) in Postgres.
    • A scope will consist of access type and domain.
    • Access type is either read or write. Having one level does not imply having the other i.e. even if you can write that doesn't mean you can read
    • Domains will be admin, executive, and elections.
    • E.g. write:admin allows a user to write to admin-level objects, but not read them.
    • scopes are created when the user is logs in and are only applied for the session.
  • Add an expires_at column, which is a datetimetz of when the token expires.
  • Add an is_revoked column, which is a boolean that is true when access is revoked or the token has expired, false otherwise
  • Change the primary key from the computing_id to the session_id.

Access Token

  • Stateless JWT that contains:
    • iss: domain name of the web server (https://sfucsss.org atm).
    • sub: computing ID of the user.
    • iat: UNIX epoch time in seconds when the token was issued.
    • exp: UNIX epoch time in seconds when the token expires.
    • scopes: string array of scopes.
    • sid: session ID, which is the ID of the refresh token that generated this access token.
  • Whenever a request that requires authorization is accessed, this should be sent by the frontend.
  • The backend will verify this checking the signature (using HS256) and the expiry.
  • If the token has expired, send status 401.
  • If the token has not expired then trust the contents of it for GET requests.
    • POST, PUT, and DELETE all require verification of the sid and ensure it's not revoked.
  • Expires after 15 minutes.
Example
{
  "iss": "https://sfucsss.org",
  "sub": "compid12"
  "iat": 1234567890,
  "exp": 1234568790
  "sid": "hkljlkljsdlkjffyekd"
}

Cookie properties:

  • HttpOnly=True
  • Secure=True
  • SameSite="Lax"
  • Domain=".sfucsss.org"

Refresh Token

  • Basically our current session token, except with an expiration time.
  • The hashed value of this (SHA265) is stored as the primary key in the user_session database.
    • We don't store the raw value at all.

Cookie properties:

  • HttpOnly=True
  • Secure=True
  • SameSite="Lax"
  • Domain=".sfucsss.org"
  • Path="/auth/refresh": this indicates this token is only sent on the /auth/refresh endpoint.

Session Token

  • Contains a JSON object consisting of the user's a CSRF token, computing_id and an array of scopes.
    • The CSRF token must be sent on every POST, PUT, and DELETE requests in a X-CSRF-Token header
  • Expires after 15 minutes.

Cookie properties:

  • HttpOnly=False: it needs to be accessible by a frontend
  • Secure=True
  • SameSite="Lax"
  • Domain=".sfucsss.org"

auth Endpoint Updates

  • login: Creates the three tokens, only the refresh token is stored in our user_session table. If the user already has refresh token in the database then revoke them.
  • logout: Reads the refresh token (even if expired), sets it to revoked and sends a response to the browser to delete all three cookies.
  • refresh: Gets the refresh token from the user, verifies it has not been revoked or expired, and creates a new access token. Revokes any older access tokens. If the token
  • user: Remove this endpoint

Dependency updates

  • Instead of hitting the database, the user's access token will be read for their permissions.
  • If the access token is revoked, immediately send a 401, except for /auth/refresh and /auth/logout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions