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.
Related
I currently have this flow but I am unsure of the architecture going forward.
On my page, the user gets sent to the Slack OAuth API where they confirm scopes
User gets redirected back to my page with a one time code
Client sends a request to the server with the code
The server sends a request to Slack with the code, exchanging it for an access token
If the code and token are OK, it creates a new user in MongoDB
I made a flowchart to illustrate:
I would like the user to not have to authorize the scopes every time they want to access the service, and even if they did, how would I keep the token around in a secure manner to make requests? Would I have to create my own token authentication with login and password, or is there a better way? Should I persist this token on the client somehow and have the users be logged in that way? If so, what is the best way to do that?
Slack token generation must be one time activity per user.
When creating user in MongoDB, you should also store the generated token securely.
For later use, your application should use the stored token for any slack interactions, given that you have authenticated the user whose token you'll be using.
I have a client facing React native application.
I'm using JWT for authentication with quickly expiring access tokens(10m) & long lasting refresh tokens (7d).
I have two servers, one for auth & one for fetching other things.
ex: server.com/auth, server.com/activities
My question is, how to have a good refresh mechanism here ?
Ex: If a user logs in after 2 days and queries an API through my app, how should I send him the new access token back (using his refresh token) - keeping in mind my auth server is at a separate location ?
The obvious solution I see here is to contact /auth from /activities, get the new tokens and send the new tokens in the header of the response, while on the client side keep checking for new tokens in the header & saving them if present.
Is there a better solution than this ? Is this even a good solution ?
An perhaps better option is to look at using the Backend For Frontend (a.k.a BFF) pattern to secure SPA applications.
See
Backend For Frontend Authentication Pattern with Auth0 and ASP.NET Core
The BFF Pattern (Backend for Frontend): An Introduction
Securing SPAs using the BFF Pattern (once and for all)
What I would do, and as far as I know is what most people do is to have your API (/activities) respond with 403 if the access token is expired. The frontend should catch these responses and then ask the authorization server for a new access token based on the refresh token you have. The AS will respond with a fresh access token, which the frontend can now use to send to the API. Usually this exchange will happen automatically and the frontend will eventually retry calling the API with the new access token.
If the refresh token happens to be expired, then the authorization server will respond with a 403, which is a signal to the frontend app that it should ask the user to log in again.
I wrote an API that uses JWT to authenticate the incoming requests.
I connected an ASP.NET Core application to this API. When the users login to the application, it asks the api if the credentials are goods, and if they are the api sends back a JWT token to the application.
This application finally stores the JWT to an httpOnly cookie on the client.
Now, I want to use the "User.IsAuthenticated" feature to displays the name of the actual user if he possesses a JWT cookie.
To do so, I wrote a JWTManager which analyze each requests of the application and if the user possesses a JWT cookie, the Manager will authenticates the user with HttpContext.SignInAsync by decoding the JWT, verifying his authenticity from the api then reading all the claims it contains before adding it to the User Session.
Tldr, I discuss to the api with jwt but I use cookie sessions on the application, sessions that I ironically create from jwt too.
My question is, do I need to keep sessions ?
Basically, I implemented the cookie session to use the [Authorize] annotation. But because the api already uses it, I can simply verify if the api returns unauthorized to stop the user from accessing the content he isn't authorized to use.
To display the name, I can avoid the User.Identity.IsAuthenticated and simply look for his JWT, verify if its authentic from the api then displays his name from the JWT. If he hasn't a JWT, I can display "Sign in" instead of his name.
What is the optimal way to use JWT ?
I choose it to reduce the calls to database from the api and to make the cross applications easier to use. And avoiding session will also reduce the memory used by the server to store them.
But is it worth it ? I'll ask the api if the JWT is authentic at each request from the client, then decode the JWT to at least write the username on the navigation bar to each requests (yes I can use cache and ajax to avoid reloading the navbar at each request, but I still need to verify if the user has access to the content).
Is it more efficient than just use a session with several roles and [Authorize] my content ?
Or finally my mixed use of both feature is efficient ? (Authenticate and discuss with the api from jwt will using session on the application)
The Setup
We’re building a PWA (progressive web app). The main components are the app shell (SPA) and the API. The REST API will supply the data needed for the app, while the SPA will handle the rest (as per Google recommendation).
The Problem
Authentication of the end-user seems problematic because the web browser needs to be accounted for. We want the user login to persist through closing down the browser.
We’ve done the research about the possible ways of going about it, however we’d like to ensure that we’re not going in the wrong direction.
Solutions we’ve considered
Session based authentication - the user sends username and password to /accounts/auth and receives a HTTP only cookie with the session ID. The session needs to be stored in a database or Redis. The issue with this option is that cookies are automatically sent by the browser therefore we need a CSRF protection in place. Using the Synchronizer Token Pattern a new token would be generated every time a state changing request has been made e.g. POST. This means that the application needs to supply a CSRF token with every request so that the PWA can send it via AJAX. We determined that it’s not ideal as the user can send multiple post requests in a quick succession making some of them fail and resulting in a bad user experience.
We could also use this method without the CSRF by limiting the CORS policy to same domain and adding a header requirement which technically should stop all CSRF, however we're unsure how secure it would be.
JWT token based authentication - the user sends username and password to /accounts/auth and a new JWT token is issued. The JWT then needs to be stored in localstorage or a cookie. Using localstorage means that JWT is XSS vulnerable and if the token is stolen, an attacker can impersonate the user completely. Using cookies we will still have a CSRF issue to resolve. We considered a double submit cookie method but the CSRF would only refresh every time the JWT is reissued which creates a window for the attacker to find out what the CSRF is. It is not clear which method is best to use.
Session based authentication + JWT token authentication - the user sends username and password to /accounts/auth, a session is created, a HTTP only cookie is set in the browser and a JWT token is sent back to the user. The PWA can authenticate requests with the JWT and whenever the JWT expires the app calls /accounts/auth again to acquire a new one. The /accounts/auth endpoint would still need to be CSRF protected, however the impact of it on usability would be minimised.
There seems to be a large amount of articles claiming that localStorage is insecure and shouldn't be used so why are high profile organisations like Amazon still recommending it? https://github.com/aws/amazon-cognito-auth-js - this SDK uses localStorage to store the token.
You don't need to generate new CSRF token each time a client make a request. It's much easier to use a scheme like token = hash(id + secret + current_day). You only need to update it once a day, or even employ mixed scheme (if the token is invalid today, but is okay for the previous day, the server accepts the operation and returns new token in a predefined header for client to renew it). You may also use the cookie as an id, making the token totally stateless and much easier to check, no need to store them in the database.
Here is how I look at it.
JWT token authentication : with this approach, you can always use a time-bound token with its expiration set to say 2 hours or something?
Or another approach would also be to try and see how you could use some of the approaches the Credentials Management API suggests for example, auto-sign-in of users whenever they come back.
Stuff like 2-step verification with OTPs for instance; for very important features in your web app can be a choice. In this case basic stuff are tied to whichever one time authentication method you have.
Actually, you can also use user-defined pins or short codes (seen a lot in banking apps) to grant access to some features in your web app.
Hope this helps, or sparks some ideation.
I'm working on a cloud service authentication system and I'm not entirely sure what the optimal way to handle authenticating requests is. We're planning to run our image server as a separate process from our API server so that we can scale them independently of each other. Handling request authentication with API keys is fairly simple, because we can just have the image server store its own API key and check that requests provide it in a header (over HTTPS obviously), same with the API server. For users though it gets more complex.
Right now we have it setup so that the API server will handle generating a session token and storing users in its database, however what we'd like to do is use 3 servers:
authentication server
API server
image server
and have the image and API servers authenticate requests against the authentication server. How exactly should this be done though? It seems like a bad idea performance-wise to hit the authentication server for every request that the API and image servers make. Can/should a token be verified from a different server than it was created on?
So for example: can/should I pass the token received from the authentication server to the image server, verify that the token came from "my.auth.server" and check that the user ID is the right one? Would JWTs be a good type of token for this?
Here's an alternative approach.
Your authentication issues a JWT token that is signed using a secret that is also available in your API and server images. The reason they need to be there too is that you will need to verify the tokens received to make sure you created them. The nice thing about JWTs is that their payload can hold claims as to what the user is authorised to access should different users have different access control levels.
That architecture renders authentication stateless: No need to store any tokens in a database unless you would like to handle token blacklisting (think banning users). Being stateless is crucial if you ever need to scale. That also frees up your API and image servers from having to call the authentication server at all as all the information they need for both authentication and authorisation are in the issued token.
Flow (no refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server.
User uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
There are a couple of issues here. Namely, that auth token in the wrong hands provides unlimited access to a malicious user to pretend they are the affected user and call your APIs indefinitely. To handle that, tokens have an expiry date and clients are forced to request new tokens whenever expiry happens. That expiry is part of the token's payload. But if tokens are short-lived, do we require users to authenticate with their usernames and password every time? No. We do not want to ask a user for their password every 30min to an hour, and we do not want to persist that password anywhere in the client. To get around that issue, we introduce the concept of refresh tokens. They are longer lived tokens that serve one purpose: act as a user's password, authenticate them to get a new token. Downside is that with this architecture your authentication server needs to persist these refresh token in a database to make them revokable before they expire (think "revoked" column in tokens table).
New flow (with refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server, alongside a long lived (eg: 6 months) refresh token that they store securely
Whenever the user needs to make an API request, the token's expiry is checked. Assuming it has not yet expired, user uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
If the token has indeed expired, there is a need to refresh your token, user calls authentication server (EG: POST / auth/token) and passes the securely stored refresh token. Response is a new access token issued.
Use that new token to talk to your API image servers.
OPTIONAL (banning users)
How do we ban users? Using that model there is no easy way to do so. Enhancement: Every persisted refresh token includes a blacklisted field and only issue new tokens if the refresh token isn't black listed.
Things to consider:
You may want to rotate refresh token. To do so, blacklist the refresh token each time your user needs a new access token. That way refresh tokens can only be used once. Downside you will end up with a lot more refresh tokens but that can easily be solved with a job that clears blacklisted refresh tokens (eg: once a day)
You may want to consider setting a maximum number of allowed refresh tokens issued per user (say 10 or 20) as you issue a new one every time they login (with username and password). This number depends on your flow, how many clients a user may use (web, mobile, etc) and other factors.
You can store some additional metadata (ip, geolocation, device, browser cookie, etc.) alongside refresh tokens. That way, you can be smart about when to reject malicious usages of refresh tokens in case it's compromised.
Common Q: Why store all refresh tokens, and not just revoked ones? You could do that. Ask yourself the following: Will I, at any point, need to have a functionality where I can dynamically revoke valid refresh tokens, based on some arbitrary, regulatory, legal, integrity, security etc. criteria? If so, the least you will need is a list of all issued tokens, plus any data required to implement the criterion logic. Example: Due to regulation, I need to ban all EU users equates to a delete from refresh_tokens were user_ip in <... eu logic ...>
one of the best ways to use is a JWT Token , you can generate and share it between all your servers and validate it on the server side .
https://jwt.io
also I think the best architecture to use in this case is the micro service architecture