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.
Related
The key tells who you are..
The secret tells if it's true...
But, both of these can be achieved by having a unique secret string. Sort of a token.
What is the advantage of one approach over the other?
The OAuth process has more to do with just using the key and secret. In short this is what happens. The key/clientId and secret cannot be used to call API
you give a button on your page/app to authorize with the key and redirect_url
user clicks and provides their consent
the provider calls your redirect_url with a code
the code is packed with the secret, key and redirect_url and sent to provider token url to get the access_token and refresh_token
you can then use this access_token to call the api
the access_token has an expiry, so a refresh request needs to be made again using the key, secret and refresh_token
I work with Pathfix and do this for a living. We essentially take your key and secret and complete the whole process and store the tokens for you. You can use our universal endpoint to make all your API calls and we keep your tokens alive and stamp you API and complete your request for you :)
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.
I'm playing around with DNN 9 and it's implementation of JWT at the moment.
Their implementation is here - https://github.com/dnnsoftware/Dnn.Platform/tree/development/DNN%20Platform/Dnn.AuthServices.Jwt
I'm wanting to write microservices in Docker containers that all look back to DNN's SQL. However, I need to understand how to verify the JWT that will be sent via the client to make sure it hasn't been tampered. DNN's web api implementations do this automatically. The problem is I don't see how I can verify that the token is valid because there is no 'secret' that i have to add.
I would want to get the JWT from the DNN enpoint and use this in a microservice which isn't running with DNN but will be able to read the data from the DNN database.
Could anyone provide any input?
Thanks :)
If the services have access to the DNN database then you can use the validation as implemented by the referenced code.
It seems that the tokens are not real JWT tokens, in the sense that they are self-contained, though they are not real reference tokens either. The tokens are persisted in the database, but contain public data as well.
How this is implemented: the token is identified by a sessionId and the secret is a concatenated string, converted to byte array:
var secret = ObtainSecret(sessionId, portalSettings.GUID,
userInfo.Membership.LastPasswordChangeDate);
The data is a JWT. It contains a Header, a Payload and a Signature.
From the received token first the Header (and scheme) is validated. Then the RAW token is read, expiration is verfied and the existence of the SessionId is checked, which is added as claim (TokenId).
The final step is to lookup the user from the store (cache / database), using the SessionId:
private UserInfo TryGetUser(JwtSecurityToken jwt, bool checkExpiry)
{
// validate against DB saved data
var sessionId = GetJwtSessionValue(jwt);
var ptoken = DataProvider.GetTokenById(sessionId);
When the SessionId is not found, the token is not valid. Again expiration is validated.
And finally the received data is compared to the persisted token, line 423:
if (ptoken.TokenHash != GetHashedStr(jwt.RawData))
This should prevent the token from being tampered.
This means for you that you can use the same code for your microservices, provided that the services have access to the DNN database. Call ValidateToken(), which will return the username when valid or null when invalid.
An alternative is to publish your own JWT tokens like I described here. You can create a central API or use a fixed, shared secret. E.g. a certificate that is available to the microservices. In that case you are dealing with self-contained JWT tokens which can be validated using the default validators. And you don't need access to the database.
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/
I need some advices on how to secure my application:
I have a REST service, using Spring MVC 3
I have my client application, using Ext GWT 2.2
Users credentials are available on the server side only.
SSL available
REST services should only be used by authentificated users.
I have read about HTTP Digest , token based authorization, oAuth etc, but I need some clarification and advices on how to secure my application, and which methods are the best in my case.
here is the methodology we created for our applications, works very well, and is very secure.
this is a very conceptual explanation, there is a lot of code that backs this up, FYI
When user authenticates or creates account, the server returns an x.509 certificate, base64 encoded, that is unique to for the user. The server stores a copy.
Everytime the client needs to access the REST API, client creates a JSON string comprised of the following.
The Users Unique ID (UserID)
A GUID or UUID, that guarantees this call is unique,(CallID) (protects against replay attacks)
A Dictionary (collection of Key/Value) of each parameter of the rest call
we then encrypt that string with the x.509 public key, and encode it back to base64 string, and take this encrypted value and add the UserID to a json object we call the token.
we then put the token into header of each call, and call it something like: X-Auth-UserToken
On every call the server takes the token, looks up the users certificate based on the userID, then verifies that the encrypted part of the token can be decrypted with the private key that the server holds for the user.
once decrypted, the server takes the CallID and verifies that it is unique, against its own calllog db.
if it checks out, the user is authenticated.
once the user is authenticated, you can apply your own authorization rules based on the users uniqueID.
of course, all the above is over SSL.
let me know if you need me to drill down on any parts.