4

The motto of the upcoming question is "I don't know what I don't know". I would like to know if there are downsides or security risks with an authentication implementation.

Right now, I'm storing a JWT in an HTTP only cookie to send it from the client (React application) to the server (Spring Boot/Kotlin application). This removes the XSS vulnerability.

The JWT follows the basic principles (encoded secret, expiration date, issuer check, etc.). The server has servlet filters that check an existing cookie for validity on every request. When signing in via the client, the server responds with a valid JWT:

sign in

The client will send its cookie with every request, which is furthermore checked for validity by the server's servlet filters on every request. When these checks are positive, the user is authenticated with Spring Security.

As described above, the JWT expires after 1 hour, 1 day, or whatever is configured. That's why I need to refresh it some way or another. Now, instead of using a refresh token and placing it in the client's local storage, I decided to just make a small request to the server and create a new JWT, which is send back via the response again:

refresh

Again, when the refresh endpoint is called, the servlet filters will check for validity. So only an already authenticated user will receive a new JWT token that way. Some invalid JWT will not receive a new JWT. I'm calling this endpoint from the client in an interval and therefore regularly extend the expiration date of the JWT inside the cookie.


What I'm aware of:

  • With the current refresh mechanism, an access token can be valid indefinitely (when the user is signed in regularly).
  • I also don't persist valid tokens or sessions in the database, so I can't really invalidate specific user sessions "globally" that way, as the cookie is the only source of truth. But this has nothing to do with the refresh token, I could create such whitelist/blacklist via the user ID instead.

If something really bad happens, I could still

  • ...change the expiration date of all JWT to 0, so every authenticated user will be unauthenticated the next time he sends a request.
  • ...or I could change the JWT secret, from which one no request will be authenticated anymore.

My question is: Has what I'm doing (replacing the JWT inside the cookie) any more downsides?

0

1 Answer 1

1

This is an answer based on a theoretical standpoint.

What you are designing is non-standard. Non-standard security is always a risk. And you have to decide what your risk appetite is. If you have a problem in your implementation, you are running the risk that your all users might be exposed or user data etc. Are you willing to take that risk? That is your choice to make, not mine.

Standards like basic security, oauth2 flows, Kerberos, etc have been developed to standardize login flows to avoid possibly risky implementations. And also to give the ability to implement things like single sign on, and authentication between different services.

There are a lot of things that are risks, that dont involve specifically your flows for instance:

  • Is everything TLS?
  • Is there sensitive information in the JWT?
  • What password policy, can we enumerate the login?
  • is the JWT signed correctly? how are the signing keys stored?
  • Are CSRF and CORS in place?

What i don't really like is your /refresh solution. In standard oauth2 flow, you keep doing requests against the resource server until the server responds with a 401 UNAUTHORIZED the client then takes the refresh token and tries to refresh, and then re-does the orginal request. If the refresh failed, they are officially logged out. If they refresh and redo the request and it fails, they are logged out.

When you visit the site after beeing away for a while the client will check for a refresh token, if it exists it tries to refresh and then you can continue where you left off. Otherwise you need to re-login.

In your solution you need an authenticated user to essentially poll the refresh endpoint on regular intervals to get a new token.

Problems with that solution:

  • If i leave the page and come back after my JWT has expired, i can't refresh and i need to re-login. Which means i might need to re-login several times a day.
  • excessive need of traffic, not good for mobile users, or when you have a poor connection.
  • If server is redeployed and is taking too long time, everyone might not be able to refresh and all will get logged out.
  • complicated logic to understand when a token should be refreshed or not. Could i send in an old token and get it refreshed? could i steel someones old token and refresh it?

Other comment:

This feels more to me like a session based login containing a JWT. How does this solution scale? thats why you usually separate out and have a issuer server, that purely issues and validates tokens. So that you can add on multiple servers and microservices.

That concludes my answer, but without looking at the implementation, this is what i can theoretically threat model around this.

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.