ataverascrespo / RecordRack

Digital music collections and social platform
https://recordrack.ca
GNU General Public License v3.0
1 stars 1 forks source link

Refresh tokens do not persist across devices #7

Closed ataverascrespo closed 9 months ago

ataverascrespo commented 11 months ago

So, my implementation of OAuth 2.0 means a user can only really be logged in on one device. When a user signs into a new device, a new refresh token is submitted to the DB and checked at the set interval of access token expiry. So if I sign in on two devices, the first device will be looking to validate a refresh token that has now been overriden by the second device.

That's where the 'fork in the road' happens. If I want users to be able to log in with several devices, it'll take some pretty extensive DB schema / back-end changes, but it will ultimately improve UX. Or, given that I don't really have an active userbase, it might not even really matter.

I'm gonna start this issue regardless just to document my decision making from here on out.

ataverascrespo commented 11 months ago

What will the back-end changes look like to support multiple device sign-on?

My mind immediately goes to changing the current refresh token field (which just stores a singular token ID right now) into something that stores a JSON-like map object of tokens (lets call it refreshTokens). When a user signs in, the generated ID can be appended to the refreshTokens object. So now, when the access token expires and the refresh token is being validated, the back-end can look through the refreshTokens map and validate the refresh token exists.

That seems like a clean enough approach. I'll have to make sure to implement a clean up function i.e when a user log outs, delete their refresh token from the map.

I'll look into how to best store this in Postgres (probably jsonb). Who knows when i'll do it though

ataverascrespo commented 9 months ago

Took me 2 months but I finally got around to it 🥇

Before, users could only be signed in on one device since the generation of a new refresh token would overwrite any previous tokens.

Refresh tokens are now stored in a JSONB column of RefreshToken objects within the Users table. When they sign in, a new RefreshToken obj is added to the JSONB list. When the refresh token is being validated, the back-end can check whether this JSONB column contains the refresh token - meaning users can now be signed in on several devices

I added some clean up logic with a log out endpoint, as well as clearing the list upon password reset. Now I just need to add a cron job that does regularly scheduled (once a day? once a week?) clean ups of ALL expired tokens on the DB and we be golden