15
votes

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 !

1

1 Answers

14
votes

Regarding access token and refresh token

Consider the access token to be a "dirty" token. Token you share a lot. I does not have to be one server you pass the token to, can be many. Because of this the attack surface rises. If one server does something stupid like writing tokens into server logs and then exposing the logs to the world, you want to limit the negative impact, therefore the access tokens are short lived, to limit the time the attacker can do something malicius.

On the other hand a refresh token is a "clean" token. Something you store for yourself to remember and use it only if you must. Of course if the attacker gains physical access to your computer and the user agent, then it is game over. But here we try to protect from the remote attacker. The refresh token should only be used when talking to an auth server or an auth endpoint. If you decide to make it a cookie - you can - just remember to limit the directory path to just the REST endpoints the token is to be passed to.

Regarding your solution

It looks good to my eye. Maybe I would not implement the XSRF Token just to save effort. I mean, what is the worst thing that can happen, if someone tries to attack over CSRF? He might be able to make you refresh your token. But the token will not be exposed to the attacker only because of CSRF.

One more thing

I like your question. It is really well written! : )