The Crystal Programming Language Forum

How to implement an auth strategy using sessions and JWT

Hey folks. I am trying to move away from basic auth on my toy project and wanted to do a sessions + JWT implementation. I plan on hand rolling this to understand the entire auth process (which has always scared me in the past)
Can you critique my auth strategy and let me know if it makes sense?

Auth strategy:

Goals
    - faster query as sessions db doesnt needs to be queried for more than once every n days
    - jwt is only usable for n hours, so if its stolen it wouldn't cause as much issues
    - sessions are long running and if the user returns back after some time, they don't need to relogin
    - if the user returns back after a very long period of time, they will need to relogin
    - key idea; using a session id as a refresh token

- Register
    - user sends email & password using form
    - if the email is already used, server sends back error
    - (email verification TBA later)
    - server stores email & encrypted password in db
    - server starts the login process

- Login
    - user sends email & password using form
    - if password doesn't matches, send back error
    - server creates a sessionid for the that email with n months expiry time and saves in db 
    - server creates an encrypted jwt containing some of the user details and the sessionid, with n days expiry time
    - server creates a cookie containing the jwt and x hour expiry time

- Auth check for guarded apis (via middleware)
    - user makes any api call which needs auth
    - if no cookie
        - redirect users to /login
    - server extracts the jwt from the cookie, and the user details and sessionid from the jwt
    - if jwt is not authentic
        - return error
    - if auth cookie has NOT expired
        - continue with requested api function
    - if auth cookie has expired AND jwt has NOT expired
        - generate new jwt with new expiry. set cookie with updated expiry using new jwt
        - continue with requested api function
    - if auth cookie has expired AND jwt has expired AND session id doesn't exists
        - delete cookie and redirect to /login
    - if auth cookie has expired AND jwt has expired AND sessionid has expired
        - delete sessionid
        - delete cookie and redirect to /login
    - if auth cookie has expired AND jwt has expired AND sessionid has NOT expired
        - generate new sessionid. replace old sessionid in db
        - generate new jwt. set cookie with new jwt
        - continue with requested api function
    - user details and session id are extracted from jwt
    - user details are used in authenticated api

- Logout
    - get the session id from the jwt
    - delete the session id from db
    - delete the cookie
    - redirect to /login

I don’t understand the purpose of using JWT for this if you’re keeping a sessions list anyway. Just for the sake of it? JWT doesn’t provide any benefit of using the session id directly (it can be signed and encrypted without the additional overhead).

This looks like a typical example for Why JWTs Suck as Session Tokens | Okta Developer

i wanted to cut out the need for a sessions db. While this aproach doesn’t cuts it out altogether, it does means that every guarded request only needs to hit the server once every n hours, instead of each and every time.

From what I understand, decoding and reading JWTs is much cheaper than making a db connection and getting the session info.

Essentially I wanted the performance of JWTs but also the ability to logout and protect the user from cookie stealing attcks.

I would not necessarily assume that to be the case. Or at least not that it makes any noticeable difference in almost any imaginable use case.
My advice is to keep things simple. Less room for error. Only optimize for performance when you know it’s necessary and can back that by numbers.

In general: Your use case is not a use case of JWT.

Thanks. Would this be a better strat? It would be using only session id.

Purely Session based Auth strategy:
Goals
- Using only sessions
- if user is using site frequently, their session goes on infinitely
- if user doesn’t uses site for some days, they have to relogin into the site
- Refresh sessions every n hours
- update sessionid frequently so that anyone who has stolen the cookie can only use it for limited time

- Register
     - user sends email & password using form
     - if the email is already used, server sends back error
     - (email verification TBA later)
     - server stores email & encrypted password in db
     - server starts the login process
 - Login
     - user sends email & password using form
     - if password doesn't matches, send back error
     - server creates a sessionid for the that email with n hours expiry time and saves in db 
     - server creates a cookie containing the sessionid and x days expiry time
 - Auth check for guarded apis
     - user makes any api call which needs auth
     - if no cookie
         - redirect users to /login
     - if no sessionid in the db
         - the cookie is deleted and user is redirected to /login
     - if sessionid has expired
         - generate new sessionid with new expiry. 
         - set cookie with updated sessionid with its own updated expiry date
         - continue with requested api function
   - server gets the user details using the sessionid
   - user details are used in authenticated api

- Logout
     - get the session id from the cookie
     - delete the session id from db
     - delete the cookie
     - redirect to /login