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?
Related
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.
In Oauth and Openidconnect, the appserver endpoint invocation starts the Oauth flow and the app server gets the token from the auth server and is able to pass the token to resource server to access resources (delegation) on behalf of the resource owner.
The token exchange happens between the app server and resource server, and the token never arrives at the end users browser.
I'm working on a web api (aka app server) that will be consumed by a mobile app. There is no other server involved. Presently the login endpoint returns a signed JWT token to the user if correct credentials are supplied (validate against the db). User places this token in the header of the subsequent request.
Assuming I don't want to have a user db and validate logins, and instead delegate the auth check to another service like azure b2c or firebase (that use the Oauth), then I assume the flow is like given below:
Api registered the firebase/azure b2c (let's call this the provier) clientid, secret.
User invokes login endpoint of my api
The api invokes the provider's Oauth flow.
User gets popup to authenticate with the provider.
Eventually the provider will send the token (containing the claim like username) to the api (aka app server)
Does the user get back any token? Otherwise, when the user makes subsequent endpoint calls, then how is the endpoint able to identify who is this user and whether he is already authenticated?
Although it is okay to send back the access token to the user , but from the security best practise 's point of view , it is better not to do it which I quote the reasons as follow from this:
Because of the issues outlined above, the best security recommendation
for an SPA is to avoid keeping tokens in the browser at all. This can
be achieved with the help of a lightweight back-end component, often
described as a Backend-For-Frontend.
The backend component can then be configured as a confidential OAuth
client and used to keep tokens away from the browser. It can either be
stateful and keep tokens in custom storage, or stateless and store the
tokens in encrypted HTTP-only, same-site cookies. Whichever variant is
chosen, the backend component creates a session for the SPA, using
HTTP-only, secure, same-site cookies, thus enabling a high level of
security. Such cookies cannot be read by scripts and are limited to
the domain of the SPA. When combined with strict Content Security
Policy headers, such architecture can provide a robust protection
against stealing tokens
Also from here ,they suggest for mobile app 's OAuth2 best practise , it should perform the OAuth flow inside a system browser component.
Considering that for tokens I use randomly generated unique strings (not JWT), what the authentication flow should look like in microservice architecture?
What I've come up with so far is the following:
when a user logs in, the backend app sends the provided username/pass to my Authentication microservice
Auth. microservice verifies username/pass, generates token, saves it in its Users db (+associates the token with the current user). Then it returns the token to backend app.
Backend app creates a session (stores it in some in-memory db), saves this token in session, and responds to browser with a cookie.
On every subsequent request user sends cookie > backend app retrieves token from session data > sends it to Auth. microservice which verifies token and grants access.
Is this a solid authentication flow or am I missing something?
My web service expects both browser and non-browser clients. And I use token based authentication to make the service stateless.
I store the token as cookies because I want when some Ajax calls initiated from the web page, the token is sent along automatically by the browser.
But for a non-browser client, how to handle cookie? Do I just manage the cookie as a plain HTTP header?
The ideal way to do this on a non-browser client is to use something like the OAuth2 protocol. This protocol was designed to securely handle stuff like this for both browser AND non-browser clients.
Here's how it works:
Your service exposes an OAuth2 endpoint, typically /oauth/token.
Your client sends a form-encoded POST request to /oauth/token, specifying what 'type' of OAuth2 the client is using. In the case of a non-browser client, you'd most likely supply grant_type=password in the body of your POST request.
You also include your username/password to authenticate yourself.
What your client will then get BACK, is an Access Token / Refresh Token that should be securely stored on your client.
If your client is a mobile device like iOS, you'd store the Access / Refresh Tokens in the iOS keychain -- if you're on Android, you'd store those tokens in Shared Preferences. Either way -- these are 'secure' storage locations meant for holding confidential information like tokens.
Then, when you need to use those tokens to authenticate against your service, you can simply POST to your API with that token, and bam, you will be authenticated.
This is the ideal way to handle token stuff in most situations. I'm the author of an authentication library in Node called express-stormpath, and this is how I do it as well.
I'm using DRF, and I've enabled Session Authentication so that I can view the browseable API in my browser. In my mobile app, i'm using token authentication. I'm just curious, how does session authentication differ from token authentication in this context? It seems to me that they are more or less the same because with session based auth, a session id instead of a token id is stored in a cookie and used in the same way. Can anybody explain it better?
Sessions and cookies are mainly meant for browsers where the browser will take care of sending the cookie with every request to the server. This why the CSRF protection is only enabled by default for session authentication. On the other hand, token authentication will most probably used with non-browser clients where it stores the auth token and send it with each request in header. This token is not necessarily obtained by exchanging the credentials for a token similar to what happens in session authentication. There can be a use case where an admin generates these tokens and hands it to some other system client that will invoke your API, and clearly this client does not have to have a username and password to exchange it for a token.