Using JWT authentication across multiple microservices - authentication

I have search the web for an answer about this issue, but nothing is quite similar to the setup I have.
So I have a single page application and 3 services:
Backend service - service A
Service for serving static files of the SPA - service B
Authentication service - service C
The flow is as follows:
A user visits the site by going to the / of service B gets redirected to the /login of service B.
The user enters the credentials and they are sent to service C to perform the authentication process and to get the permissions for the user, this data is sent in a JWT.
Service B then puts it in a cookie and returns it to the user's browser.
Then the user performs a task which requires that JWT, so I have to send that cookie to service A, but there is a problem, I can't do it, the cookie is only for service A.
https://auth0.com/docs/security/store-tokens - this link is an example of a source I found that is talking about the issue of where to store the tokens for SPA.
It says there that I should use a cookie to store the JWT if :
If have my own backend
If the backend is in the same domain as the site itself.
The problem is that my backend has a different URL, it is a completely different service, so using cookies wont be the solution, or at least that is what it seems to me.
Then it says:
If your single-page app has a backend server at all, then tokens should be handled server-side using the Authorization Code Flow, Authorization Code Flow with Proof Key for Code Exchange (PKCE), or Hybrid Flow.
The problem here is that they don't even mention how and where to store the JWT so I can access it from multiple domains.
I have not found a clean way to save that JWT on the user's browser and send it in every request that I am doing to the backend.
The solution I need is to save the JWT in a secure way in the browser of the user, allowing me to send it to any backend service I need to.
Thanks for reading thus far and for helping!

One solution is to send the requests to the backend service with JWT in a query param.
You can then have a middleware in the backend service that converts it to an Authorization header so that libraries that look at it continue to work.

So that is the way I chose to implement the solution, but first, few clarifications.
When a browser tries to visit the site, as stated in the question, will be redirected to the /login route to verify the user.
But if the user is nonexistent, then I will let the user to see the site but with minimum permissions.
So if the user is authenticated, the cookie with contain the jwt with the needed data.
If the user is some sort of a guest, service B will still return a cookie, but will indicate that the user is a guest.
The way I chose to implement it is:
Because of the explanation above, we always get the cookie from service B, meaning we can always tell our site save it in the LocalStorage of the browser, so I decided to save the JWT in it.
For each fetch request that I make to service A, I will set a header named Authorization that the value of it will be Bearer <the jwt token> (insert the jwt inside <the jwt token>) as stated in this MDN article about authorization.
About security:
So because saving the JWT in a cookie that is related to service A is not possible (service B and A are from different domains), we are left with the LocalStorage option.
LocalStorage is not the most secure way, it is by default vulnerable to XSS attacks,
but, as stated in this answer, by mikejones1477, modern browsers have strong defense against XSS, and the LocalStorage is not vulnerable to CSRF.
So, essentially, there should be extra care about XSS attacks, but that is the way its made possible to pass the token between services from different domains.

Related

API Authentication for PWA

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.

Securing Express API

I'm writing a web app with a separate frontend and backend. The frontend is written in React, and the backend is a node.js server running an Express endpoint. How do I ensure that only my frontend can access the API, and not anyone else? My API URL is exposed in my frontend client side code, so anyone can see that.
I added JWT authentication to my API, but I still need to have an unprotected /login endpoint in order to generate the JWT token, and in order to login to generate the token, I must post both a username and password from my frontend, which other users can see, since it's done from the client side.
What is the proper way of securing an API that is hosted on a separate backend like this, so that only my frontend can access it, in a way where nobody can see what credentials are being used to access the endpoint?
You can't. Your API is on the internet. Anyone can access it. You can require an account and login credentials for the account before allowing access to the API, but once someone has an account and credentials, they can access the API from their own script rather than via your web page. This is how the web works. Not much you can do about it. And credentials being used by the client cannot be hidden. All data that is EVER on the client can be looked at by a hacker on the client. This is the way of the web.
Larger companies will typically monitor their API usage to look for inappropriate use. This includes rate limiting, detecting behaviors and sequences that are not typical of a regular human user. When they detect inappropriate use, they will often disable that action or ban the offending account, either temporarily or permanently. This is also why some pages use techniques to detect if an actual human is individually causing the operation such as reCaptcha. For example, on stack overflow, when editing comments or posts, I often run into rate limiting where it tells me that I have to wait a bit before it will accept my edit.
There is no absolutely secure way to store credentials in a client. The most common scheme for credentials is to require username and password (securely over https) and then when that is accepted on the server as legit credentials, some sort of token is issued to the client which can be used for future API calls. That token may be in a cookie or may need to be manually included with each subsequent API call (the advantage of a cookie when using APIs from a browser is that the cookie is automatically sent with each subsequent request).
If the token is a cookie, then the cookie is stored in the browser's cookie storage and an expiration can be set for it. The browser's cookie storage is protected from access by web pages from other sites, but can be accessed by someone on the local computer (it's stored in the file system).
If the token is not a cookie, just returned as a token, and the client wishes to store it, there are a few other places that Javascript provides access to in order to store it. Local storage has similar security as cookie storage. It is protected from access by other web sites, but can be accessed by a person on the local computer.

REST API authentication for web app and mobile app

I'm having some trouble deciding how to implement authentication for a RESTful API that will be secure for consumption by both a web app and a mobile app.
Firstly, I thought to investigate HTTP Basic Authentication over HTTPS as an option. It would work well for a mobile app, where the username and password could be stored in the OS keychain securely and couldn't be intercepted in transit since the request would be over HTTPS. It's also elegant for the API since it'll be completely stateless. The problem with this is for the web app. There won't be access to such a keychain for storing the username and password, so I would need to use a cookie or localStorage, but then I'm storing the user's private details in a readily accessible place.
After more research, I found a lot of talk about HMAC authentication. The problem I see with this approach is there needs to be a shared secret that only the client and server knows. How can I get this per-user secret to a particular user in the web app, unless I have an api/login endpoint which takes username/password and gives the secret back to store in a cookie? to use in future requests. This is introducing state to the API however.
To throw another spanner into the works, I'd like to be able to restrict the API to certain applications (or, to be able to block certain apps from using the API). I can't see how this would be possible with the web app being completely public.
I don't really want to implement OAuth. It's probably overkill for my needs.
I feel as though I might not be understanding HMAC fully, so I'd welcome an explanation and how I could implement it securely with a web app and a mobile app.
Update
I ended up using HTTP Basic Auth, however instead of providing the actual username and password every request, an endpoint was implemented to exchange the username and password for an access key which is then provided for every authenticated request. Eliminates the problem of storing the username and password in the browser, but of course you could still fish out the token if you had access to the machine and use it. In hindsight, I would probably have looked at OAuth further, but it's pretty complicated for beginners.
You should use OAuth2. Here is how:
1) Mobile App
The mobile app store client credentials as you state yourself. It then uses "Resource Owner Password Credentials Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.3) to send those credentials. In turn it gets a (bearer) token it can use in the following requests.
2) Web site
The website uses "Authorization Code Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.1):
Website sees unauthorized request and redirects browser to HTML-enabled autorization endpoint in the REST api.
User authenticates with REST service
REST site redirects user back to website with access token in URL.
Website calls REST site and swaps access token to authorization token.
Here after the website uses the authorization token for accessing the REST service (on behalf of the end-user) - usually by including the token as a "bearer" token in the HTTP Authorization header.
It is not rocket science but it does take some time to understand completely.
3) Restricting API access for certain applications
In OAuth2 each client is issued a client ID and client secret (here "client" is your mobile app or website). The client must send these credentials when authorizing. Your REST service can use this to validate the calling client
I resolved this for my own API quite easily and securely without the need to expose any client credentials.
I also split the problem into 2 parts. API authentication - is this a valid request from a recognised entity (website or native app). API authorisation, is that entity allowed to use this particular endpoint and HTTP verb.
Authorisation is coded into the API using an access control list and user permissions and settings that are set up within the API code, configuration and database as required. A simple if statement in the API can test for authorisation and return the appropriate response (not authorised or the results of processing the API call).
Authentication is now just about checking to see if the call is genuine. To do this I issue self signed certificates to clients. A call to the API is made from their server whenever they want - typically when they generate their first page (or when they are performing their own app login checks). This call uses the certificates I have previously provided. If on my side I am happy the certificate is valid I can return a nonce and a time limited generated API key. This key is used in all subsequent calls to other API endpoints, in the bearer header for example, and it can be stored quite openly in an HTML form field or javascript variable or a variable within an app.
The nonce will prevent replay attacks and the API key can be stolen if someone wants - they will not be able to continue using after it expires or if the nonce changes before they make the next call.
Each API response will contain the next nonce of if the nonce doesn't match it will return an authentication error. In fact of the nonce doesn't match I kill the API key too. This will then force a genuine API user to reauthenticate using the certificates.
As long as the end user keeps those certificates safe and doesn't expose the method they use to make the initial authentication call (like making it an ajax request that can be replayed) then the API's are nice and secure.
One way of addressing the issue of user authentication to the API is by requesting an authentication token from the API when the user logs in. This token can then be used for subsequent requests. You've already touched on this approach - it's pretty sound.
With respect to restricting certain web apps. You'll want to have each web app identify itself with each request and have this authentication carried out inside your API implementation. Pretty straight forward.

API Token Safety in Angular application

I'm building an Angular app with an API backend. On a combination of pieces of advice, I built the API with a flavor of token authentication. The flow is roughly as follows:
POST to login endpoint with credentials
Validate credentials and authorization, then generate a new token
Return token to client
Client uses token via HTTP Basic to access API resources
This is all working well. The problem arises in creating a session based on this token. I don't believe I should simply hold the token on the client in a cookie, but I do need a session to persist between page refreshes, etc. My Angular app is stateless and completely populated via API calls.
I'm looking for a recommendation as to hanging on to this token on the client. I feel there's danger in holding the token in a cookie because the cookie could be stolen and simply used to authenticate as someone else, but perhaps this is incorrect.
Thanks in advance for your assistance!
The only known way for me to identify a user is to use some token on the client.
HTTP is stateless and can't know which request is coming from which user (browser). You can't identify the user by his ip address (many users are behind a router and share a connection). You could try browser fingerprinting, it can work on some browsers but not on all.
I would recommend using a cookie to store this token on the client.
They are send to the server on every request and you can do some protection to keep them from getting stolen.
To protect this cookie from man in the middle attacks you need to use an encrypted connection over HTTPS to the server.
Set the following attributes on the cookie:
HTTPOnly: cookie can't be accessed by javascript (XSS protection)
Secure: cookie will only be send over https
Path: cookie will only be send on specified path e.g. /login
I would also define an expiration date on the cookie, so the cookie is invalid in like 2 days or something.
But you are right. If this token gets stolen someone else can login as this user.
Since its an Angular app, I'd assume all authenticated methods will only be served to ajax requests (you can tell your server to only respond to ajax) in which case CORS will help you.
The only way to be completely secure is HTTPS, however this method is probably more secure than you think. Read up on CORS a bit for more info, but essentially the idea is that servers will only respond to ajax requests coming from html pages that were served by that same domain.
Pre-flight OPTIONS requests are often sent to verify this. The browser sends an OPTIONS request with an Origin header (the origin of the page) before the actual request. If the origin matches the domain of the server receiving it, the subsequent request is allowed. Otherwise, it violates the Same Origin Policy and will be rejected.
This prevents someone from sniffing out the token and sending a request with the token from a page that your server didn't serve (like something running on the hackers local machine).
If you are doing credit card transactions or anything super secure, you should use HTTPS though.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing

RESTFul Authentication with WebAPI

I have a web service built with WebAPI that accepts JSON requests and responds accordingly. The core architecture is built but there isn't any authentication/authorization.
After a lot of googling and poking around sample projects, I'm not sure where to start. I've found a ton of material from 2008 and 2009 but not a whole lot of recent guides/workflows for WebAPI / single page apps. I think the workflow should be as follows:
Check to see if the user is logged in: How can this be done with javascript? Do I send a cookie to my webAPI? If so, do I send that cookie as a parameter in the body of the request?
Let the user log in / register: How is this data encrypted/decrypted? Surely I can't be sending passwords over the wire... is this where SSL comes in?
Provide them with access to what they have rights to access: I think I got this - I can just authorize in the controllers on a per-request basis.
Any info would be awesome.
Basically you need a token based authentication or authorization.
If you are referring to the ASP.NET WebAPI, the following project will be a great place to start:
http://thinktecture.github.com/Thinktecture.IdentityModel.45/
Even if you are not using ASP.NET WebAPI, the following video is a great introduction on how to provide authentication/authorization on RESTful web services:
http://vimeo.com/43603474
To answer some of your questions:
Check to see if the user is logged in: How can this be done with javascript? Do I send a cookie to my webAPI? If so, do I send that cookie as a parameter in the body of the request?
You can use a cookie but I normally use the header in order to avoid common XSRF attacks. Cookies are automatically included whenever a http request is sent from the browser.
is this where SSL comes in?
Yes. If you are going to go ahead with the token based approach, you can use a separate server (Identity Server) to do the authentication for you.
JavaScript clients are unique. Do you have the Web API and the page serving up JavaScript in the same domain? If not, you have same origin policy restrictions. If you have the same Web application hosting the web pages and Web API, you can use forms Authn. In that case, you don't need to send the cookie containing the authentication ticket yourself from JavaScript. Browsers do that for you and that is the cause of XSRF problem. You have to be careful about JavaScript sending credentials that the end user is not supposed to know. If JavaScript knows something, any intelligent end user can get to that knowledge. OAuth 2.0 implicit grant could be a good choice. The end user enters the credentials (password) in the authorization server which issues an access token. JavaScript gets the token and presents it to the web API but it will never have access to the credentials.