How to handle refresh tokens in HttpOnly cookies with Hot Chocolate (GraphQL)? - asp.net-core

I have an Asp.Net Core 6 GraphQL API app. Server setup with Hot Chocolate and endpoints are served at localhost/graphql.
When a user logs in GraphQL resolver generates both - access and refresh tokens, and sends in response as HttpOnly cookies.
An access token cookie has a path - "/", and a refresh token cookie has a path - "/graphql/refreshtoken".
The idea is that the browser in every request should send an access token, but a refresh token must be sent only when a client hits "/graphql/refreshtoken" endpoint.
I could not find any example with my scenario. And those that I found store refresh tokens in local storage, but not the cookie.
How can I setup the GraphQL server to serve /graphql/refreshtoken endpoint?
Note: I don't want to additionally use REST for refresh tokens.
If the above approach is not achievable, how can I refresh cookie-stored tokens with GraphQL? What is the best practice?

Related

Cookie-based JWT token refresh: is a separate call to the `/refresh` API endpoint really necessary?

I'm using .NET 6 with HttpOnly cookie-based JWT authentication in my WebAPI, and I'm now implementing token refresh.
I store the JWT and a Refresh Token in cookies, e.g.:
X-Access-Token: eyJhbGciO...
X-Refresh-Token: d8085ec8-d0bc-4e5c-b6b6-cd76146c419f
Most flows I've found for token refresh look like this, with the client calling the /refresh endpoint to get a new JWT:
client sends request to server
server rejects request with a 401 Unauthorized
client requests new JWT (expired JWT and Refresh Token automatically sent to server in cookie)
server validates cookie Refresh Token, generates new JWT and Refresh Token, assigns to cookies
client sends original request to server, with the new JWT and Refresh Token in the cookie
My question is:
When the initial request with the expired JWT is received by the server, since the server already has the refresh token (sent in the X-Refresh-Token cookie), can't the server issue a new JWT and Refresh Token at that time and successfully complete the request? This completely eliminates the need for a separate request and response to refresh the tokens. This is the flow:
client sends request to server
JWT is expired, but Refresh Token is valid
server creates new JWT and Refresh Token, assigns to cookies
server successfully completes the request
Is there a vulnerability or security risk implementing the refresh this way? I cannot think of one, but I could not find any examples with this flow.
Thanks!
Why are you using JWT access tokens? If the server could respond with an updated access token by looking at the refresh token, then why wouldn't the server just look at refresh tokens every time, and then the JWT access tokens aren't needed?
The point of using JWTs, and access tokens in general, is that it allows stateless authentication with services that have no access to the refresh token store. Usually, you will have an authentication service, it stores the refresh tokens, and calls to /refresh get routed to it, and it will validate the refresh token, and issue the access token. Then, calls to other services are able to validate the access token, without needing to make any calls on the authentication service. So, the reason why they don't just reply with a new access token when authentication fails is because those services are incapable of checking the refresh token, they don't have access to the refresh token store, only the authentication service does.
If however your application is one big monolith, where every endpoint is hosted by the same server and therefore is capable of checking refresh tokens and issuing access tokens, then there is absolutely no reason for you to be using access tokens or JWTs in general. You should just use refresh tokens, which, in this case, would be better called a session token.

Can I save encrypted token in HTTP only cookie?

I'm building a single page application (SPA), which calls the GitHub API in client side with GitHub token of the users.
I want to persist the token, but saving it into browser storage (e.g. localStorage, sessionStorage, indexedDB...) from javascript is not secure due to xss.
So I thought an idea: In order to persist the token, the client (SPA) send the token to my backend API server, and the backend encrypts the token and attaches it into http-only cookie and sends it back.
When decrypting the token, the client call the backend, and the backend reads the cookie which holds the encrypted token, decrypts it, and send the raw token to the client.
I want to keep the backend as simple as possible, so I don't want to keep user sessions in backend (it requires DB to save the session information).
Is it secure?
If no, how to persist the token securely?

Oauth + SPA + API backend

I'm setting up a service which needs to authorize against an existing Gitlab as OAuth Provider.
The service is a SPA which gets served by a webpack dev server in dev mode and a nginx server in production mode.
I'm also setting up an external API which should handle the Database and make request to the given gitlab instance (for example pull repos).
My SPA is authorizing against the Gitlab OAuth with the implicit_grant flow and is getting an access token. Currently I pass the access_token after the redirect to my API backend and there I get the Gitlab userid and username via a request to the gitlab instance with the access_token. With these I generate a jwt and send it to the client (SPA) and save it there so I can authorize my API with this JWT.
How would I handle the initial access_token in my backend (cause I need the token to make gitlab calls)?
Currently I'm thinking about writing it to the user in the database and get the user everytime he makes a request (normal passport flow), so I also have the token. But what if the token gets invalid or expires?
Should I use an interceptor in the backend and if the token is invalid (gitlab would give me a 401) redirect the 401 to my client, let him get a new token and pass it back to the backend, generate a new JWT, send this again to the client and let him do the same request as original reuested(via interceptor, too)?
Or should I just redirect the 401 to my client, let him get a new token, let him post this token to for example /renewToken and save the token to the database and use the old JWT?
Hope someone can help me unserstand this flow.
The Credential Management API should be what your looking for on the client. That will retrieve the id and access tokens to that you can compare access tokens with your server/ap and then validate the id token.
Haven't seen a Git example but there are Google and Facebook examples.
You could let the user send the initial access token and your backend API will just act based on the initial access token. Seems to me that it is not necessary to produce another JWT token in this case.

JWT authentication using cookies with KONG API Gateway

We are implementing a sample application using Kong API gateway with JWT authentication plugin.
As refer in this thread, there are two ways to store JWT in the browser. Web storage or cookies. But web storage (i.e. session storage and local storage) can be vulnerable to cross-site scripting attack(XSS). So other option is cookie. (Though CSRF should be taken care off)
I have two questions,
If we use web storage to store JWT then is there any way to stop XSS. If yes then how it will work if the same page is open in the new tab or reload the same page ?
Using cookie: We are able to send the cookies in the request. But KONG is authenticating the end point URL only if the JWT is set on headers (Authorisation: Bearer token) and not authenticating using cookies. Is there any way to verify JWT which is set in cookies using KONG API Gateway ?
There is nothing wrong about storing JWT in webStorage, unless you store sensitive data in your JWT (but you should never ever do that, since you can decode it easily). The point is that your token shares a secret, that only your servers knows (that's what makes it secure), you should just put an expiration time to make it a lot safer.
And no, you cannot pass a JWT token in cookies, it's only in headers (here Authorization), I don't know about KONG API, but they should not allow that !
(ref about JWT is here)
In order to add to #antoine2vey answer,
It looks like your on page application is being served from a protected API in Kong at the "/" (slash) resource. I would suggest that you would be able to get the page content from an unprotected "/" (slash) resource and then run javascript code would have access to the cookie and would be able to perform the request to the protected resource passing the JWT token in the header where Kong would be able to validate for you.
Does this make sense?
Cookie based authentication is implemented. https://github.com/Kong/kong/pull/2973

Multiple SPA with JWT Authentication with Refresh Tokens

I have a weird scenario. I want to have a single backend API with multiple SPAs as frontend (all under the same domain but different subdomains). Here was the original idea for using JWT and Refresh tokens.
User logs in using USN/PWD.
Server Authenticates the request and sends back a JWT with an expiration and permission in claims.
The server sets a refresh token (that is stored in a data store for sessions) in a cookie for the domain and all subdomains.
Now all request send the JWT and cookie to the server.
If the JWT is expired then check that the refresh cookie is still valid and send a new JWT
Now if the user is in a different SPA under the same domain we can send a request to /token?grant_type=refresh_token which will send a JWT token if refresh token is stored in a cookie.
I would like to know drawbacks to this approach.
Another approach I read (https://stackoverflow.com/a/29088725/4664675) looks interesting as the JTI is basically the sessions ID.
I am not too worried about 15 minutes expiration tokens and a refresh token of about 1-week sliding session. All connection from the SPA to API are over HTTPS as well.
What would someone recommend the best way to handle this situation (One login that is used for many apps like Google does for mail, drive, photos, youtube, etc.)? I like the idea of JWT so that I don't have to hit the datastore on every request.
A little further down the road, I would like to make native apps that consume the same API so an authentication and authorization process that can handle both would be ideal! Seems like I need a Single Sign On approach?
PS. This is all from research and this will be the first authentication/authorization workflow that I will be writing.