Microservices authentication architecture with passport.js - node.js

I'm writting a toy application for practicing microservices and authentication on nodejs (expressjs).
I have a react client, an authentication service and other services (they just respond "Hi" so far).
The client will be hosted in a CDN.
The auth service listens on port 5000 (for example)
The rest of the services listen on port 6000-6100.
I have a redis db to store session information (oauth token provided by twitter).
A mongodb where the application information is stored (not relevant for this question).
The idea is that an unauthenticated client goes to the auth service by clicking the Twitter button (SSO). Then the auth service obtains the generated twitter oath token and it sets this token in the redis store. Then the token is accessible to the rest of the services so they know if a request is authenticated or not by checking if the it already exists in the redis store (if the user removes its account, it will also be deleted from the redis store).
I send the twitter token back and forth from client to server once authenticated.
I find this approach pretty simple (others use an nginx proxy for authentication but I see no reason for that, except if the services are hosted in different domains, but I don't understand it very well) so I'm worried I'm missing something about security for example.
Questions:
Is this approach correct?
Is it safe to share the twitter token (I think so)?
Is there any security issue I'm not noticing here?

Using this approach you will have to validate the token in all your services, if you are okay with this then you are probably fine.
The twitter access token may have an expire time that will make it necessary to use a refresh token to get a new access token from the auth service:
When the access token expires you would return a 401 to the client, from the Service X that you are trying to talk to.
The client would have to call the Auth service providing a refresh token, getting a new access token
Finaly the client would be hitting the Service X again with this new access token, have it validated and get the expected response from Service X.
In my recent assignment I wrote a micro-service that proxied all the tokens, using this approach my proxy handled everything from auth to roles and sending 401's for expired tokens and revoking refresh tokens etc. I think this gave me a greater separation of concerns.
Important Note: In the refresh token scenario above my proxy only would experience load for an invalid/expired accesstoken, whilst in your scenario any service could be reached with invalid tokens...
Another approach would be to let Service-A and Service-B call the auth service to validate the tokens, but this would infer a lot of more traffic between the services since each HTTP request with a token has to be validated. In this scenario as well a invalid token request would reach your Service X and hence infer some load on it...

Related

validate userId given by okta

I have an app which consists of frontend server and a backend server.
front end server connect to corporate OKTA mechanism so that user logins through their corporate ids into my app.
After this step, frontend server connects with some backend work at backkend server (node js). Their it passes in the request body the user id so that we can finally log that the below processing is happening due to user X.
Now suppose user A logs into the app . Now during the APi call to backend server, he can modify the arguments being passed to the api and somehow change the userID.
Is there some way by which backend server validate that userID is not compromised ?
Regards
If your front-end app uses OIDC to log a user in, then you should be able to get back an id_token, which has user identity in it. You can pass this token to your back end app for API calls. This approach is not ideal though, as your backend will still have issues with trust, as it does not know if the token presented by the front-end app is a legitimate one and not stolen.
Other way is to harness traditional authorization_code flow (again, assuming you can do OIDC with you company's identity provider). There your back-end would retrieve the tokens for you directly from authorization server and can get a user's identity from it. Based on that it can then create a session and embed user info into it. It's a bullet proof approach lacking trust issues from above.

How to exchange data from database in Microservices

I am looking for advice on data sharing between microservices.
My app has 3 services but in this case, I need to share data between only 2 services:
-Main (Handling requests, store user data)
-Upload (Receive files and modify)
Before the user can send a file to the server, the server must verify if that the user exists and whether he has permission to send files.
My idea for it is to create a private API in the main service with an Nginx API gateway, so the upload service can make HTTP requests and fetch data about the user and permission. Does it make sense? or there is an easier solution for it? I use express and postgresql.
It is a good approach, but perhaps, the main service should be the auth server.
I mean, in order to ensure that a user has the proper permissions to do an action you have to use something to identify the user and something that cannot be altered, this normally is achieved using a signed token.
This token is created by the auth server when the users log into the application and when it is passed to a service, this service can check against the auth server if the token is valid and if the user identified by the token has the correct permissions to execute the action.
This process is very similar to the one you have explained before. In your case, the user service will be the auth server that is responsible for the authentication and authorization of users and the upload service is the one that is consumed
As you have two microservices(Customer, File upload).
The best way to communicate to other microservices is through the HTTP call(GET,POST,DELETE,PATCH) exposed by that MS.
In your case Customer microservices has few endpoints like GetCustomer,CreateCustomer,DeleteCustomer,PatchCustomer. Before uploading the file you can call the GetCustomer API for checking the customer's existence in the system. If it is present, then proceed with further processing of file data.
As mentioned by JArgente, Use the authorization token for authentication and authorization of microservice endpoint. Pass that token in HTTP_Header while calling the Microservice and validate that against your Authorization server. You can write the interceptor, which validates the token.
As long as your main server can authenticate the user, and verify the user is authenticated, you can implement a JWT token.
If your client is already sending a JWT token to your main server, the same token can be used to communicate with other microservice.
If not you can always generate a new JWT token to be sent to your micro services, without maintaining any centralize database
var token = jwt.sign({ user: 123 }, privateKey, { algorithm: 'RS256'});

Authentication architecture of VueJS(or React or Angular) application in front end using authorization code grant

I am working on an application where the front end is VueJS and the backend is NodeJS and ExpressJS.
The NodeJS, ExpressJS will be hosting REST API's and I want to secure them using Azure AD. I want to use Auth Code flow.
My question is: I have put my thoughts in the diagram, is this the right approach?
This approach looks good to me. I am thinking of it as an advanced version of something like JWT (https://jwt.io/) based authentication. Please see the steps below for JWT:
The client requests authentication by providing credentials.
The server provides the client with the token that is encrypted using the private key present in the server.
The JWT is stored in client's session and is sent to the server anytime the client requests something from it requiring authentication.
The server then decrypts the token using the public/private key and sends the response back to the client.
A session is validated at this point.
With the architecture you have described above, it does the exact same thing except the means to encrypt (generate) and decrypt (verify) the token exists with Azure AD. Below are the steps for achieving authentication based on your architecture:
The client requests authentication by providing credentials.
The Azure AD server does a 2FA kind of thing but in the end provides the token (equivalent to JWT in the previous approach).
The token is stored in client's session and is sent to the application backend server anytime the client requests something from it requiring authentication.
The backend server uses Azure AD for verifying the token (similar to the decryption/verification step of JWT) and sends the response back to the client.
A session is validated at this point.
I would suggest a small change to this though. If you look at the step 4 above. The application server will keep hitting Azure AD every time it needs to authenticate the session. If you could add an actual JWT for this phase, it may help in avoiding these redundant calls to Azure.
So the steps described above for JWT may be added after the 4th step for Azure AD described above i.e. create a JWT and store it in clients session once everything is verified from Azure and then keep using JWT based authentication in the future for current session.
If required, JWT can be stored in the browser cookies and calls to Azure AD can totally be avoided for a specific period. However, our objective here is not to decrease load on Azure AD server but just suggesting a way of using JWT in this specific situation.
I hope it helps.

NodeJS Authentication for Multiple RESTful API services

I would like to seek help from you guys.
I have multiple RESTful API services running in NodeJS Express. Each API is hosted by different NodeJS with different port. And in our front-end, it is accessible via reverse proxy.
We are now moving to a secured services. However, there's a problem in authenticating with the services. The front-end should request 1 auth token upon login that can be used in accessing the internal API services (API is also accessible in our public domain /api/).
How can we solve this problem?
Current Setup
You could issue a signed JWT token upon login (see https://jwt.io/).
The front end application has to send the token back with each API call.
Each API server has to know in advance the key (public key or symmetric key depending on the type of the signature algorithm) and use the key to check the signature of the token is valid.
If it is valid, the API server knows it can trust the token content, and decide whether to serve the request. The token would contain the identity of the user, expiration time, ...
Note that signing the token does not encrypt the data: if you need to convey sensitive data through the token, it needs to also be encrypted
Thus it is not necessary to establish a session and then share the session across the many API instances. Knowing the key is enough to trust the token content
To pass the JWT in API calls you can use a header:
Authorization : Bearer theBase64EncodedToken
Of course, it is up to you to check if this scheme satisfies the security concerns related to your application.

Should my app issue it's own access tokens, when using external oauth2 provider (facebook)?

I would like to give the users a possibility to login with some external oauth2 provider (facebook) in my app. The client's part is running on mobile device in a native app.
I am not sure which of the approaches below should I prefer ?
Should the client send the user's access token by facebook with each request ? At each request backend asks facebook to validate the access token. Based on the validation's result, backend performs authorization and return corresponding result to the client.
Should the backend ask facebook to validate the access token only at user logon, then issue its own access token, return the access token back to the client and client will use this access token at making requests to the server to avoid contacting facebook at each request ?
I have read some questions about how to implement the auth with facebook and most of the devs are using B, but I haven't seen any explanation why is it good/bad to use A ?
What I see as benefits of the solutions:
backend doesn't need to care about issuing, refreshing, validating access tokens since this is done only by facebook's authorization servers.
this solution seems to be more effective, since it does not require to connect to facebook at each request.
Security tokens issued by Facebook are signed with a digital signature. The API server only needs access to the public key to validate the signature. There's no need at all to contact Facebook after the user authenticates.
A reason to issue your own tokens after the user signed in with Facebook could be to add claims to the token. But obviously having your own authorization server comes at a cost. It's up to you to weigh the pros and cons.
If you do decide to have your own authorization server, make sure not to write your own! There are open source options like Thinktecture IdentityServer.
I will vote for option B and here is my explanation,
Your API must authorise the request every time with some auth token , which cannot be external provider token, in such case anyone with an access token (eg: other developers) of other provider can access your api, basically there is no auth here.
When your sever issue access token, it's easy to validate and when needed could be revoked easily (eg: on password reset)
While authenticating , your server has fully control over issuing access token , so the validation is made only once and doesn't have to do every time while calling the API.

Resources