I understand that the authentication process with access/refresh tokens works like this:
- Exchange username/password for refresh_token
- Use refresh_token to get access_token
- Use access_token for requests (no DB call needed)
- If access_token is expired -> use refresh_token to get a new one (DB call needed)
Process to manage/revoke access:
- Exchange username/password for refresh_token
- Store refresh_token in the DB
- Check revoked flag in DB when using a refresh_token to get an access_token
- Block by setting revoked flag
DB interactions: Only needed for refreshing tokens. i.e. frequency depends on the access_token lifetime.
User Experience: Login required when
- first visit
- refresh_token revoked
- refresh_token expired
Security implications:
- refresh_token stolen: vulnerable until manually revoked or for a long time
- access_token stolen: vulnerable short time. Cannot be revoked
- logout: access_token remains valid until expired/cannot be revoked
Without refresh_token: +No long lived vulnerability -Bad UX. User needs to login frequently
Now I am wondering why we cannot just use the access_token as the refresh_token:
- Exchange username/password for access_token
- Store access_token in the DB
- Use access_token for all request (no DB call)
- When expired: Check DB if revoked flag set. If not -> Create new access_token and set revoked for old token. (optionally, only allow this for x time after expiration. This is the equivalent to an expiration date for the refresh_token)
Now UX/security/DB_call_frequency seem to be identical. So why do we need a seperate refresh_token?
The only argument I can see is that separating them reduces the risk that a refresh_token gets stolen because it is sent less frequently.