Verifying jwt tokens [rsa] - cryptography

A collegue and myself have been trying to understand how jwt tokens verify tokens, but from our reading we seem to be confusing ourselves.
Please can someone help confirm whether my thinking is correct
Tokens are signed using the private key. The signature is a combination of the header and payload encrypted using the private key and added to the jwt as the last part, the signature.
In order to verify the token the receiver can replicate this process using the public key. They encrypt the header and payload to see if it the same as the signature. Note this is not decryption. The receiver is not decrypting the token (this is the main thing we are unsure of).
-The receiver cannot issue new tokens as they do not have the private key to encrypt a new token with.
I have read the jwt documentation on both RS256 and HS256 and still struggling to confirm my thinking, hence the post.

Tokens can be digitally signed using a key pair, private and public, or hashed using a secret key:
RS256 :RSA KeyPair with SHA256. Token is signed with private key and verified using the public
HS256: HMAC key with SHA256. The key is the same to sign and verify
A compact JWT looks like this hhhhh.ppppp.sssss
hhhhh: Header of JWT, includes the algorithm used to sign the token. e.g {"alg":"RS256","typ":"JWT"}. Encoded in base64url
ppppp: Payload of JWT, include some useful claims like sub, iss or exp. Encoded in base64url
sssss: Signature of JWT , performed on the concatenation of the base64 url encoding of header and payload using the specified algorithm and encoded in base64. E.g b64(signature(hhhhhh.pppppp))
Answering your question, you are refering to RS256 using a key pair where the client verifies the token using the public key (a verification with HMAC key would mean client and server share the key)
The token is signed (not encrypted) with the algorithm I wrote above. To verify, the client verifies that signature match with the first part of the token hhhhhh.pppppp using the provided public key. Digital signature verification is a standard operation supported in all modern languages. Note that is not the same as encryption/decryption

I was dealing with the same question when I was learning about multiples signing algorithms. So, when we are singing and validating sings with RSASHA256 in JWT, this is the process:
Sign = RSA(SHA256(base64(header) + "." + base64(payload)), private_key)
Sign is valid, if RSA(Sign, public_key) equals to SHA256(base64(header) + "." + base64(payload))
For more information, visit this link: https://www.cs.cornell.edu/courses/cs5430/2015sp/notes/rsa_sign_vs_dec.php#:~:text=RSA%20Digital%20Signatures&text=To%20sign%20a%20message%20m,result%20equals%20the%20expected%20message.&text=That's%20the%20textbook%20description%20of%20RSA%20signatures.

you can get a detailed description of JWT auth tokens in official website
https://jwt.io/introduction/

Related

Securing a JWT token

In general, JWT has an encoded message with a signature. The signature uses for checking the genuinity of the data. My question is, this signature is for assuring the client about the server, but how server can trust the client? In other words, if a client sends a JWT to the server, how the server can be sure this is the right/authenticated client?
My second question is about JWT's lifetime. I know there is a claim (exp) which can be set to indicate JWT's expiry. But what if the client changes that claim? Should I keep expiry date on the server to make sure the JWT is still valid? Wikipedia says: To validate the session stored in the token is not revoked, token assertions must be checked against a data store. This renders the tokens no longer stateless, undermining the primary advantage of JWTs.
Given a JWT, the server knows that the client is legitimate by verifying that the HMAC of the header and payload is equal to the signature. The server has a secret key that it uses when computing the HMAC, so if someone wanted to create a fake JWT with a proper signature, they would need to have access to this key.
Your second question shares the same idea as the first. If a client wanted to change the expiration of their JWT, they would have to recompute the signature, and to do this successfully, they'd have to know the secret key.
The point of using JWTs is not to store data like the expiration date on the server, all of this data lives inside the token itself, and the integrity of this data is protected by the secret key used to compute the signature.
JSON web token (JWT) can come in two flavours. Typical, the most widely used form is to use JWT with a JSON web signature (JWS). In security world, this provide integrity. Other form is JWT with JSON web encryption (JWE). This form provides both integrity and confidentiality.
So if you have a specific requirement to identify that you get a valid, condifential JWT, then you should adopt JWE based approach. You can read more about this in RFC7516. For encryption, you can use either symmetric or asymmetric keys. Once you receive JWE based JWT, you can validate that it was sent by intended party by successful decryption of the JWT payload.

Auth0: Managing authentication on Lambda functions

Current Implementation
My current application utilizes Vue.js + Auth0 on the frontend.
Vue.js utilizes AWS API Gateway, POST/GET methods are sent via:
https://xxxx.execute-api.us-east-1.amazonaws.com/dev/
On the API Endpoints that require authentication I have a "jwtRsaCustomAuthorizer" Authorizer. Which is documented here.
Remaining Concern
However is validating IF the token is valid enough? In this scenario I want to make a POST function that will do two things:
Update the users app_metadata
Save data associated to user
How do I KNOW User id auth0|123456 is who they say they are?
With the JWT being validated by the Authorizor, do I know the token hasn't been manipulated? E.g. if I just decode the passed data, can I assume the userID is valid?
The short answer is: You do not really care in the frontend. Validation of the token normally happens via the backend, which is in your case through the jwtRsaCustomAuthorizer you were talking about. If the backend trusts the token it returns data, and if it does not it returns an authorisation error.
Your backend, and in particular jwtRsaCustomAuthorizer, does validate that the content of your JWT token is valid and trusted. A JWT token consists of three parts. The first part describes the algorithm used. The second part is the payload, which contains the claims, a nonce, an issuer and an expiration date. The third part is used to verify if the JWT token is issued by a trusted party by using a secret and generating a signature with it. In your case you are using RS256 with a private and public key pair.
Since the first two parts of the JWT token are used to generate the signature, you cannot change the algorithm or the payload without invalidating the signature. Since RS256 uses assymetric encryption using a public and private key pair, you can either verify the JWT token by performing the same steps using the private key and comparing the newly generated signature against the signature in the JWT token, or in case of your api endpoint, using the public key to decrypt the signature and checking that against the first two parts of the JWT token.
jwtRsaCustomAuthorizer ensures that the JWT token was created by auth0 by checking the JWT token against the public key that is provided by auth0. If the signature matches the payload, it means that the issuer must have had access to the private key, which is only available to the issuer. This allows you to trust the payload.
You can find more information via jwt.io and this stackoverflow question on the difference between hs256 and rs256.

Can you modify the header of a JWT token after it is created (after it is encrypted and signed)?

I know that a JWT token contains a header section that is BASE64 encoded.
Scenario:
Decode the header
Change the value of one of the parameters present in header, like for example kid parameter
Encode the modified header
Replace the initial encoded header with the new encoded header in the JWT token
Questions
Will the token still be valid?
Or when it is initially signed, the header is also considered when creating the signature, thus if after that you modify the header, the token is considered invalid?
For a signed token (JWS), the signature is computed using the payload AND the header.
If you alter the header or the payload then the signature part becomes invalid.
You can give it a try at https://jwt.io/
Please note there was a known attack that consisted into a modification of the signature algorithm to none and the signature itself allowing payload modification without warning for vulnerable libraries.
Refer to this detailed article for more information.
Yes. You can try this site, if want to modify from an existing token: https://token.dev/
Someone can not change the header/payload unless has the secret key. if he/she has the secret key they can change the JWT token.
For instance, if you are using nestjs to register JwtModule you have to read the secret key from the config file to avoid revealing the secret key. as below
JwtModule.register({
secret: 'read this from config file',
signOptions: {
expiresIn: 60 * 1000
}
}),
For more information, you can watch this video

Are Json Web Tokens secure enough? And how to secure payload?

When I go to https://jwt.io I see this encoded token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
If I go to https://codebeautify.org/base64-decode , copy-paste token value and push Decode, I get this:
{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"John Doe","iat":1516239022}
If I switch from HS256 to RS256, I now get this token:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM
And it also can be easily decoded with base64. So, my question is, whether it is expected behaviour or not? And if yes, what is the reason to use different algorithms (HS256, RS256 etc.), if whatever algorithm we use, we can easily read the contents using just base64 decode?
Well Jwt is not meant to secure the content it is used to verify a claim, ie when you sign a request using jwt, when decoding it the user/sytem must have the secret key. So to answer your question yes it is the expected behaviour, the base 64 encoding is only meant for transportation over the URL and not to secure it. The last bit if i may clarify the verification of a claim is simply to mean you are what/who you tell the system you are and that the content of the signature has not been altered even alittle bit, any changes to any part of the encoded signature will result to signature failure; hence the claim would nolonger be authentic or true. To see this just try to encode something like this in your terminal
import jwt
encoded=jwt.encode({'name':'some name'}, 'somesecretkey',algorithm='HS256')
then copy the resulting token and then remove or add asingle letter to the string and try decoding using the same secret key and watch it fail or try the same at codebeautify again

Authentication/Decryption using a subset of Key

Is there a cryptographic system where a user(s) can be authenticated (or they can unlock a document) only if they present a subset, of more than one, the of valid keys?
Thanks in advance.
Non-anonymous authentication
If you don't require the users contributing to the successful authentication to remain anonymous, it's easy: The server generates a random nonce and sends it to the subset of users. Each user signs the nonce with his/her private signature key and sends the signature to the server. The server verifies each signature and if enough of them are present then the subset has successfully authenticated.
(Anonymous) Decryption
Someone else here might know of an RFC or a library for that purpose, but If there is none, I would design it like this: Split the secret into n parts where k of them are necessary to recreate the secret using Shamir's Secret Sharing. For each of the n users encrypt a different part of the split up secret with his/her public encryption key. When k of them decrypt their part of the split up secret, they can recreate the secret.
If the public key encryption is deterministic you can even make it anonymous in the sense that if you can get to the secret you can check that each other subset of k users would also be able to get the secret: In preparation of the protocol run you also have to designate a fixed x-coordinate for each user in addition to the public encryption key. When a subset of users successfully recreated the secret and thus the polynomial, they can evaluate it at each of the users x-coordinate and encrypt it with their public key. If the result is identical to those generated by the server, every subset of k users can decrypt the secret.
(Note that deterministic encryption has some caveats. For example, if the plaintext space is small, an attacker can just encrypt each plaintext and compare the result to the given ciphertext.)
Corollary: Anonymous authentication
Using the anonymous decryption you can create an anonymous authentication protocol by having the server encrypt a random nonce for k out of n people in the way described above and send it to the subset of users. They decrypt the nonce, check that each subset of k users would also be able to decrypt it and send the nonce back to the server.