JWT security in OAuth 2.0 and OpenID Connect - node.js

I have decided to jump on the bandwaggon and start using OAuth 2.0 and OpenID Connect for the authentication and authorization of my next project, but I'm struggling to understand how a JWT can be secure.
I am using Angular 8 for the front end with a node.js backend and Auth0 as my the identity service provider (the wrong terminology, I know. Forgotten it.)
I have watched two or three PluralSight courses on these subjects but none really go over using the JWT on a node.js back end, mostly they concentrate on the .NET stack which takes a lot of the labour out of it I guess.
My problem is this: how can I be sure that the JWT token sent to my API is one that comes from Auth0? I understand that the token has a signature, and I imagine Auth0 have some private secret they use to sign the JWT, but what is to prevent some malevolent entity creating a JWT with exactly the same content and signing with a different secret and sending that to my API? In the .NET samples I've seen, I see no mention of checking that the signature's secret corresponds to Auth0's. What checks are necessary on the API — .NET, node.js or otherwise — to ensure the JWT is authentic?
And how would this work with nodejs?

I'm not sure if I understood you correctly or what, but JWT is signed and verified by the same secret (if HMAC algo is used), so the answer to your first question would be:
if it's tampered, you will be notified during validation, because signing with a different secret is what gives it away, that the token has been compromised.
Not sure what libraries are you using, but for Node.js, the jsonwebtoken package has a jwt.verify(token, secret) function, that takes in your token and secret values as arguments. This is basically all you need and can have for verification.

Related

Correct Application Structure to Safely Verify Cognito JWT Tokens

I'm building a React application that uses API Gateway and Lambda on the back-end. I'm going through the process of integrating Cognito authentication. I've completed the following:
Generate user pool
Upon login redirect to my React application with Auth Code
Extract Auth Code and send it to Token Enpoint
Receive back the id, access and refresh JWT tokens
I covered all that in detail in a post here: AWS Cognito Notes
What I'm confused about is the concept of verifying the signature of the JWT tokens. The AWS Docs describe how to do that here: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
In short I have to download the JSON Web Key and then match it to the key on the tokens. It's not clear to me how this makes the process any safer. That key is publicly available. If I was conducting a man in the middle attack I could simply get that key and then attach it to my phony JWT token.
Which makes me think that I have a fundamental misunderstanding of this process. Should the Auth Code and JWT tokens not be sent to the React app in the first place?
Should I be setting the User Pool redirect URL to API Gateway, and have that trigger a Lambda function (that contains the client secret), to retrieve the JWT Tokens and THEN send the JWT Tokens to the React app? But then I would have the same problem of not knowing if the Tokens were legit I think? The tokens much be verified AT THE CLIENT, right?
If anyone has any insight on this or could point me to a good article I would much appreciate it.
You can use an API Gateway Authorizer to do this for you. It will check the header for ID Token and check if it is valid for your userpool. Expired and invalid tokens are rejected.
You can read more about this here: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
The answer to this was that the JWK can be stored in any capacity with the client. The JWK is publicly available, however the public key cannot be used to fake the signature itself, because the signature can only be generated with the PRIVATE key.
I did a full write up on this topic here:
https://ncoughlin.com/posts/verify-decode-cognito-jwt-tokens/

Correct strategy for auth in an API

I want to design a GraphQL API. This API would be used by some browser apps and also open to be used directly for people that want to create their own scripts/generate reports etc. The API would rely on a third party app supporting Oauth Openid Connect (okta) for user and role management. It would be written in Django.
Because JWT is a recommended way of protecting GraphQL APIs and also because OIDC uses JWT tokens. I thought of a simple way, where the API would simply accept the JWT tokens issued by okta. This works, but I see a lot of latency when API is asking okta validate the token (this latency might be smaller in production, because I'm testing on a free trial auth0 instead of production okta). So I think that maybe my API should issue its own JWT tokens. I can think of three strategies here:
Leave it as is – only use the OIDC JWTs.
Introduce a login mutation or a login REST endpoint, that would accept OIDC above and issue JWTs that can be used for all other operations.
As above, but also allow the direct use of okta's JWTs (I'm not sure if I can implement it with Django's auth system, so that if a token is recognised, the OIDC is not called).
Which of these three is the correct (and maybe intended by the OIDC designers) way to protect my API?
JWT token doesn't need to be validated by Okta (generally by IdP). You just need to get used public key (it can be found as jwks url in discovery response) and then can you can verify signatures without any IdP call.
IMHO you can get 2-4k validations/sec easily.

Correct Passportjs strategy to use (hash vs jwt)

I have a Laravel app which I'm trying to convert to NodeJS. In the original app we have an API for which access is protected by random generated tokens - assigned to each user and stored in our DB. We automatically generate this secret token when a user first registers then they use it for as long as they would like to use our services. (We verify subscription details for users using these tokens).
I'm trying to replicate the same on NodeJS but I'm a bit lost about the right authentication strategy to use, as passportJS has JSON Web Tokens (JWT) and 'hash'. They both seem correct but I can't figure out the difference and which would be most appropriate in this case.
If hash is the correct strategy would I have to use JWT to generate the token and assign it to each user? Probably I haven't understood properly the concept of hashes and token for authentications. What are the differences between hashes and token for authentication purposes?
I did some more research and found out that the JWT are not exactly what we were using or what we need for our app. We simply create SHA hashes for each user based on personal details and a secret key. This hash is now created and used in the new application correctly. It was simpler than I thought. And for those wanting to learn a bit more about JWT, this Medium article could help a lot:
https://medium.com/vandium-software/5-easy-steps-to-understanding-json-web-tokens-jwt-1164c0adfcec

Correct Micro Service JWT flow

I am currently building out a micro service architecture and started with the auth server and client. I also wanted to confirm the best flow of authenticating a user with a token.
In the above image. Step 3 is were I start getting confused.
I thought of 2 solutions to the problem.
One every api passes the token to the auth server and waits to get approval that the token stored inside matches the db and it is still valid.
Two is to include a secret phrase in the JWT token and just have the API service parse and check for itself if the token is valid.(The secret phrase would be so that if a hacker tried to fake a token and it parsed to a valid id somehow the phrase would be off without the secret code used to encrypt the token. Which I don't even know if it is possible. If not then I guess 2 would be the best course of action)
A hacker cannot create a valid JWT token if he does not know the the signing key. If he somehow manages to get that signing key it is reasonable to assume that he is able to get your "secret phrase" also.
About the checking: JWT tokens can be checked by the API service as they contain all the information needed (except the signing key that must be known by the API service). The expiration can be checked here also. Anyway, you also need the information stored inside the token, like user ID. You should do this if you want better scalability.
The only reason why you would need to check a JWT token against a third Auth service is to see if it has been invalidated; for this you need a central service although you could replicate the list of invalid tokens to all the API services for better resilience.
You really don't have to forward the request to Auth-server to validate the JWT token. A JWT token is like a bill note, once it's signed it can be validated by anyone who is sharing the key.
I would recommend you to have an edge service in front of all your API-services. The edge service either shares the key by which JWT token is signed by Auth service or has the public key to verify the signature.
Once the signature is verified, the edge service can extract the required information from the token and add it to request header. Your downstream services can consume this information according to their need.
You can use Https to enforce that your request isn't intercepted by anyone over the network. In case, even if someone tries to mess up with the JWT token, the signature won't match and you can detect that. Please go through JWT/KONG: Cannot create JWTs with a shared secret to know more about creating-parsing the JWT token with public-private keys.

Generate token after login nodejs API

I am creating an API using nodejs and express. I need to provide local username/password authentication. I may need to provide additional authentication in the future so I am using passportjs as it seems the most flexible/plug-able.
The API will be used by a web application as well as a mobile application. Instead of having to pass the username/password with every single api request I was thinking I could let the user login and provide the client with a token. The client can store the token and provide that on each api request.
I have looked at using JWT tokens ie, http://coderead.wordpress.com/2012/08/16/securing-node-js-restful-services-with-jwt-tokens/. However I am not really sure how to create a secure token with JWT. I have read that using the username in a token is a bad idea. Has anyone use JWT in node to create tokens. Got an example?
Any other modules for node that I can take a look at for token generation.
node-uuid is the module you are looking for. I use it to authenticate the users and any task that requires a random and unique identifier. Encoding the credentials in the token is generally a bad idea.
It was already built into nodes crypto pacakge.
http://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback

Resources