I have two separate Node.js services.
Service A is responsible for authenticating users. If a user successfully logs in, the user is redirected to Service B (hosted on a subdomain of the domain Service A is hosted on).
I am using JWT for authentication.
Question: How can Service B be aware if a user is or is not authenticated?
I imagine one way that Service B could be aware if they are or aren't authenticated is by asking Service A to check the JWT on each Request to Service B. But how is Service A supposed to send the JWT to the client when the client is going to be redirected to a new origin?
Is it safe to do something like:
window.location.href = 'https://b.example.com?jwt=tokenhere'
I don't believe storing the JWT on localStorage since it does not allow cross origin access.
Another bit of detail that the others haven't touched on:
If your clients are using web browsers, and if you want the user to be authenticated with both services without having to re-login (single sign-on)
E.g. if your domain is example.com, service A is at example.com and service B is at b.example.com.
Send login request to authentication service at example.com
Auth service verifies credentials and if they match, sends a cookie back to client with domain set to example.com
Client receives and stores cookie
On all future requests the browser will send the cookie to service A and service B
In service A and service B verify the JWT received in the cookie (see other peoples answers)
This method ONLY works when you're running on same root domain and your authentication service MUST be on the root domain. If you have a different setup I would recommend looking at a single sign-on product (e.g. Central Authentication Service)
Use RSA for your JWT generation. You can make the public key available to all other microservices. If the client uses CORS to talk to different services directly (vs. an API gateway), pack the JWT in the Authorization header as usual.
If your servers share a secret key you can encrypt and decrypt the token on any server. Inside the token you can write who the user is and what permissions he has. Whenever the user wants to perform some restricted action you decrypt the token and check wheter he has permission to do what he wants. Don't forget to give the token a time to live so it won't last forever.
I'm not a js guru so I won't paste code but you should be able to find an example here
Related
I am building a web application with a basic client-server architecure. The frontend runs with react (nextjs) and the backend is on rails. However, the questions will be more about the flow of the authentication/authorization + session handling on the frontend.
I am using an Oauth provider to handle the authentication but don't need any authorization from their part as I don't need the resources of the oauth provider (ex. drive, calendar etc.)
For the authorization, as I want to access resources of my API, it's the API itself that handles authorization on any request made by the client (frontend) to the rails API.
Right now for the initial authentication this is the flow I'm using, Taken from https://blog.prototypr.io/how-to-build-google-login-into-a-react-app-and-node-express-api-821d049ee670 :
Implementation details important for the following questions :
I am using JWTs as access token (those generated by my API) and I simply sign them using a secret key that's only available on my API so the access token is unreadable from the front end point of view.
On the frontend, it is a react app and I used the following package to handle the OAuth flow google-react-login
Information received, what to use from Google (OAuth provider)
1- I receive(amongst other things) an IdToken and an access token from Google. Also I'm apparently supposed to receive a refresh token (which I didn't see). For my use case, all I need is the idToken from Google is that right?
Revoking of a refresh token (logout), flow for a re-login?
2- From my understanding access tokens need to be short lived for security reasons. So I need to return a refresh token to my client app to be able to generate new access tokens frequently. However, once a refresh token hits its expriy time, do I need to log out the user and prompt him to re-login through Google and basically redo steps 1 through 5 (Please refer to Figure 1)?
How to maintain the session through the access token
3- From the frontend perspective, can I assume that simply having a refresh token means the user is logged in? Once the server revoke the access token and the refresh token that means the user is logged out and I need to ouput a view of the web application for an unauthenticated user? That means after every page reload I need to check for the presence of an access and refresh token?
Thank you
I think you could improve your security and lower complexity by one thing - replace issuing of your own JWT tokes by a custom OAuth2 server. This OAuth2 server could use Google as an authentication provider. This way, your would not know about Google and it would just use your own OAuth2 server.
Then you can decide how to use it - whether the frontend will be the OAuth2 client or the backend.
If you choose the frontend, you will use the auth code flow with PKCE (as a public client). The fronend will use an access_token to authorize its requests to the backend. This way, the frontend will handle a session using hidden iframes. See the OpenID Connect Session Management RFC.
If you choose the backend, you will use the auth code flow (with a client secret). This way, your backend can maintain the session using a cookie (with secure, HTTP-only, SameSite options).
You can read the OAuth 2.0 for Browser-Based Apps RFC for the current best practices.
I'm working on a project based on Phalcon which consists in two different stand-alone subprojects: a php + angular frontend and a php REST API.
I protected the API with OAuth2, using PhpLeague OAuth2 Server. The API server is the OAuth2's authorization server AND resource server.
This is the actual flow:
The user can browse the public endpoints of the frontend, and when hits a private page, gets redirected to the login page;
The login page has username and password, POSTs them to the frontend server;
The frontend server calls a public method on the API server, which is expecting a Password Credential Grant: it validates the credentials and sends back an access token and a refresh token;
The frontend server caches both the access and refresh token in session and uses it for some API calls: the first of those is the '/users/me', which gets info about the current user and its ACL on the frontend sections;
The frontend server sends the page to the browser, which loads its javascript files.
Now, OAuth2 states that access tokens should be short-lived and refresh-token should be long-lived: in the frontend server logic, the API calls which receives a 401 (caused by the expired access token) are retried by sending first the refresh token to obtain a new access token via a Refresh Token Grant. If this second call is rejected, I assume the user is no more logged in (refresh token expired / revoked).
The pages are using Angular to perform data and ux/ui management. My question is:
should the Angular code call directly the API server?
Actually the first thing my javascript code does is to get a config object from the frontend server, which contains the access token too, and uses it to make the calls to the API server. The problem with this is that i should rewrite again the "refresh token logic" in javascript (after it expires, i get 401s), and by what I have read on the subject i understood that it is better to not make the refresh token visible to the client (as it can generate new access tokens).
So i was thinking about a "two step approach", where every javascript API call goes to an endpoint on the frontend server which relays it to the API server, but this is obviously slower (JS -> FRONTEND -> API and API -> FRONTEND -> JS).
What is the correct approach? It's not very clear to me if the frontend should be considered as two clients (php + js) which should work separately or not, as I imagine that an hypothetical iOS app would be making calls 100% against the API server.
I have used the same approach in my own projects. The problem that we have is that the client is not secure. In order to generate / refresh a token, you need to pass secure information to the authorization server.
I have done the same as you basically, let the back-end handle the tokens and their temporary storage. You cannot and should not trust the client with important information which lets you generate tokens. In terms of delays, I wouldn't worry about it too much since you're not going to be doing that much extra work, you won't even notice the delays. I have a system like this built and used by hundreds of thousands of users with absolutely no issues.
Now, you have said a few things in here which make me wonder what you are doing.
OAuth2 is not a user authentication system, it's an application authentication system. You don't pass a user and their password and generate a token for them, you pass a ClientID and ClientSecret and they generate a token for you. Then you have an endpoint which gives you the user details for this user, you pass your userid or username and get the details of that user.
A token expired does not mean your user is logged out. Those are two completely different things. How are you going to expire a token for example, when your user wants to log out? You can't, your token will still be valid until it expires after the set amount of time has passed.
A token can be used for let's say half an hour, but your user may use the website for 1 hour. So before you hit any API endpoint, you could check ... has this token expired yet? if yes then you can go and refresh it and keep working without having to bother your user with a new login screen.
The whole point of an OAuth2 system is to make sure that only authorised clients can access it. A client is not a user, it's an application. You can have a website for example and you only want users of that website to access your API.
You can have endpoints like ValidateUser for example, where you take a username and a password and return a yes or no and then you log your user in based on that.
Irrespective of language/framework, second approach is secure and better than first one because to get access token by providing refresh token to Authorization server, it still requires Client ID and Secret which should never be passed to Browser for security reasons.
In first approach, to make a direct call it will not work if your Authz Server is hosted on different domain than your frontend server because of Same Origin policy of browsers. Even if they are on same domain, still you are exposing Client ID and Secret which will compromise your frontend server
I have some web application in my server which use ADFS for authentication let's say this is their URLs :
http://myServer/ManyWebApps/WebApp1
http://myServer/ManyWebApps/WebApp2
http://myServer/ManyWebApps/WebApp3
When the user access any URL under "ManyWebApps" hierarchy he can freely use the server function they provide through javascript and through the browser without further authentication:
http://myServer/ManyWebApps/Server/Function
Now, I need to detach one of my web apps to a new URL like so :
http://myServer/WebApp1
Will the user still be able to free access server functions under the "ManyWebApps" hierarchy :
access http://myServer/ManyWebApps/Server/Function from http://myServer/WebApp1
Note : both web applications are still on the same server and work with the same ADFS server, when the user enters http://myServer/WebApp1 he is authenticated, but will he be able to access functions on diffirent web apps on the server without further authentication?
P.S : I need to access a function without further authentication because making an AJAX request to the function while unauthenticated will cause the AJAX request to be redirected to the ADFS which it can't handle
CONFIRMED : The authentication is saved in http://myServer so no further authentication need to take place if both apps are on the same domain
When sending a request to the server, all of the user's cookies are sent including the authentication token. If the user's doesn't have the token in his cookies, the server will direct him to the ADFS. But since both web applications are under the same server, they share the same cookies which means once the user entered any address in MyServer hierarchy, he can free enter any in that hierarchy without further authentication
I own a Play Framework application acting acting as a backend server providing a set of REST APIs.
At client side, I own an AngularJS application that calls APIs from backend-server through AJAX.
Currently, I make use of a solution based on Session-token mechanism.
Meaning that each time a user logs in successfully, a cookie is retrieved at client side containing an authentication token.
At each request then, the cookie value (the auth token) providing by the client request is extracted on the server and if valid, the request is made.
Now I want to use OAuth 2.0. Reasons are? :
It's a great standard way to secure API, avoiding the use of a datastore (Memcached) to keep auth tokens at server side, as I'm currently providing.
I want to provide a better secure than a sole cookie, by providing some client_secret and nonces to avoid some replay attacks etc...
I want to restrict the amount of clients capable to call even public REST API I provide, meaning API that allows anonymous call, like listing a list of items for instance.
The point is that I don't involve a third party, since all protected resources are on my own.
I came across this article explaining how to secure internal REST API with OAuth 2.0 implementing a 2-legged instead of a 3-legged as usual.
However, I can't figure out how the Client Credentials flow could authenticate a specific user, when calling for a REST API that needs to have a user authenticated.
Indeed, Client Credentials flow seems to be based on a global client_id, client_secret keys (global to the app, so in my case to my Javascript app), and therefore not enough specific to target a specific user and controller its specific rights.
Any help would be great.
Seems like you should use "Resource Owner Password Credentials Grant" (https://www.rfc-editor.org/rfc/rfc6749#section-4.3). It is dead simple - put client ID/secret in Authorization header and put user name/password in query variables. Here is an example from the RFC:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
Server side you can check for both validity of the client (your javascript app) as well as the user. Just remember that it is impossible to protect the client credentials as it will be embedded in your (downloadable) JavaScript code. The user name/password is entered directly by the end user.
I am designing a multi-platform application at the moment (clients would include internally developed mobile apps, and an AJAX heavy javascript client initially) centred around a REST API. Since in the future the API may be open to third parties, I am looking at using OAuth 2.0 for authentication and authorization with the API.
I am trying to get my head around some of the security issues with this arrangement, particularly with regard to the javascript client. I don't want this client to behave like a third party client might, with a whole bunch of redirects and popups and stuff, which is what most OAuth documentation seems to focus on. Since it will be delivered from my own domain, I am thinking that the server side of the webapp can be the actual client, and store the client secrets and refresh tokens, while the javascript retrieves new auth tokens from the server as it needs them.
To put it in step by step form:
The user logs in using non-ajax html form, generating auth and refresh tokens which are stored server side. This sets a HTTP-only login session cookie.
The javascript client code is sent to the user's browser after login.
The javascript client makes a request to a resource that is part of its own application (not part of REST api) to retrieve the token. The session cookie ensures that the client is genuine, and the referer will also be checked. Auth token is returned.
The javascript client validates the token with the REST API.
The client can now use the token to make requests against the REST API until it expires.
If the auth token expires or the page is closed and re-opened, the javascript client can request a new token. The server side of the webapp takes care of refreshing the token and sends the new token, as long as the login session cookie is still valid.
Does this make sense, or would it leave massive holes in the system? In particular, is it insane to have a resource on the web that hands out authentication tokens based on a cookie being set?
Just make sure that any communication to browser is HTTPS, so that no one in the middle can steal your tokens. And set the "secure" flag on your auth cookies.
Most browser authorization schemes nowadays boil down to a session token that's passed in a cookie. The OAuth 2 scheme is a couple steps ahead because a) the tokens (can be) dumb tokens with no dangerous user info inside, and b) they expire.
(Just to put that comment in context: one time I popped open a session token from a site and discovered my home address and phone number was in there. Ack!)
I've seen code that does HMAC signing of requests inside the brower javascript, but it came with a huge disclaimer: don't use this in production. A signing scheme requires the client (javascript) to know a "secret" string, but the browser/javascript is so insecure that it amounts to handing your secret strings to the world.
But if you keep all your commuinication over HTTPS, then you're really just putting an OAuth twist on the familiar scheme of passing session tokens as cookies.