I'm making SPA, and decided to use JWT for Authentication/Authorization, and I have read some blogs about Tokens vs Cookies. I understand how cookie authorization works, and understand how basic token authorization works. The problem is, I don't see how refresh token fits into it, seems to me it decreases security. Let me explain, as I see it:
Cookie approach
When you authenticate user via username & password, you create session ID associated with that user. And set it as cookie, every time that client calls to your server it sends that cookie, and server can look up associated user in database or some other server side storage.
This approach is vulnerable to CSRF (Cross Site Request Forgery) To prevent CSRF You can use tokens with cookie
Server also needs to constantly look up storage to see to what user, the cookie points.
Token approach
When you authenticate user via username & password, you create a signed Token, with expiration date, email address or userID, role, etc. in payload. For security tokens should have short expiration time. Tokens can be stored anywhere Local storage, Session storage, cookies. I will be using local storage, or session storage, to prevent XSRF.
- This vulnerable to XSS (Cross Site Scripting), but you can prevent this by validating HTML input.
- Because tokens have short lifecycle, user must login again, when token expires.
Access Token & Refresh Token
So I want to use Refresh tokens to prevent user from needing to login constantly. So lets say on Authentication, I give user Access token and Refresh token, when users Access token expires, user can use Refresh token to get New Access token, This is what I don't get.
- lets say I store access token in local storage. If I also store Refresh token in local storage, I don't see any use for it. Because if attacker can access local storage and get Access token he can also get Refresh token. So in this case why not just make Access token long lived.
- If you store Refresh token as a cookie, it is vulnerable to XSRF, and then attacker can get new access token, and use that. Also at this point, why not just use Cookie authorization ? Because you already have to look up local storage to for refresh token, though this will happen less frequently than with pure cookie authorization.
What's the best practice ?
Currently I'm thinking about using:
- Access Token (local storage, short lived)
- Refresh Token (Cookie, Long lived)
- Token for Refresh Token (To protect against XSFR, Local storage, expires after one use)
Let's say it looks like this:
+--------+ +---------------+
| |------------ Authorization Grant --------->| |
| | | |
| |<--------------- Access Token -------------| |
| | & Refresh Token (cookie) | |
| | & XSRF Token | |
| | | |
| | | |
| |--------- Access Token ------------------->| |
| | | |
| |<----- Protected Resource -----------------| |
| Client | | Server |
| |--------- Access Token ------------------->| |
| | | |
| |<----- Invalid Token Error ----------------| |
| | | |
| | | |
| |---------------- Refresh Token ----------->| |
| | & XSRF Token | |
| | | |
| |<--------------- Access Token -------------| |
| | & XSRF Token | |
+--------+ & Optional Refresh Token +---------------+
Server would issue new XSRF Token every time Refresh token is used(after one XSRF token is used it stops working and server issues new one). What you think about this implementation ? In my eyes this limits server lookups to database, as it uses access tokens, access tokens is short lived, and user don't have to login constantly as it uses refresh token/cookie witch is protected by XSRF token.
Is this OK ?
Thanks !