I am working on jwt authentication based projects and I want to store the token which is created on user 's login request but this token can be decoded easily so where I have to store these token ?
//code to create token and cookie
const createToken=(id)=>{
return jwt.sign({id},secretkey);}
{....some code are written here.....}
const token= createToken(userid);
res.cookie('jwts',token,{httpOnly:true,maxAge:1000*60*60,sameSite:'lax'})
From your question, it feels like your JWT flow isn't clear. The token can be decoded - but it will only reveal some payload data and header - which doesn't contain any sensitive data.
Token's generation and explanation:
A JWT Token is formed of Header, Payload & Signature.
The header is metadata about the token itself.
The payload can be encoded in the token, i.e. the data e.g. user's Id.
Signature is created using header, payload, & the SECRET stored at the server. This process is called Signing. This 'SECRET' is what helps us to validate the signature's authenticity.
Well, so how do we make sure the data isn't modified?
A verification process is done at the server where JWT's header, payload, and secret are used to create a test signature. This signature is matched with the original signature (existing inside the JWT already) - then the data has not been modified.
Without secret - no one can manipulate JWT. That is, the verification will fail if the signatures do not match.
Token Storage:
There is some debate about whether to store the token in cookies or local-storage since both are prone to hacker attacks.
Login Flow:
The client sends a request to the server (POST - login).
The server validates the user and returns a JWT token in response if the provided credentials are valid.
The JWT token is stored in localStorage / cookies depending on the preferred choice (I prefer localStorage).
you need to send that token along with the API requests from client. I used to store in clients internal storage and used to send that token for each and every API call.
Related
I have an API which is using Azure AD B2C for authentication and on success returning access_token. Request is as follows:
POST /{tenant}/oauth2/v2.0/token
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id={client-id}
&scope=https://{tenant}/{app_id}/.default
&client_secret=sampleCredentia1s
&grant_type=client_credentials
But when I pass nonce as a query parameter, it is not returning in JWT token. Can you please share how to return a nonce in access_token for validating token against token replay attacks?
• You are right that the nonce is a strategy used to mitigate token replay attacks. Your application can specify a nonce in an authorization request by using the nonce query parameter. The value you provide in the request is emitted unmodified in the nonce claim of an ID token only. This claim allows your application to verify the value against the value specified on the request. Your application should perform this validation during the ID token validation process. Thus, the nonce value is typically a randomized, unique string that can be used to identify the origin of the request.
• Also, the nonce will be returned in the id_token and you can validate it when you decode and validate the id_token. But state is returned in the response, not in the token. Also, nonce should be validated at the client side. Please note that the generated nonce must be persisted in your web application using any of the following methods, i.e., HttpOnly session cookie and HTML5 local storage value.
Example --> ‘ window.localStorage.setItem('nonce', randomString(16)); ‘
The nonce parameter value needs to include per-session state and be unguessable to attackers. To achieve this for Web Server Clients, you need to store a cryptographically random value as an HttpOnly session cookie and use a cryptographic hash of the value as the nonce parameter. In that case, the nonce in the returned ID Token is compared to the hash of the session cookie to detect ID Token replay by third parties. A related method applicable to JavaScript Clients is to store the cryptographically random value in HTML5 local storage and use a cryptographic hash of this value shown as above.
• For validating the ID_token, find the below parameters passed in the application where the token must be validated and decoded as usual. Its nonce claim must contain the exact same value that was sent in the request: -
‘ var jwt = '...'; // validated and decoded ID Token body
if (jwt.nonce === window.localStorage.getItem('nonce')) {
// Nonce is OK
} else {
// Nonce is not OK! Token replay attack might be underway
} ‘
Please find the below example of the implicit flow containing nonce and state as a parameter of the request that would be sent by the user to the Authorization Server in response to a corresponding HTTP 302 redirect response by the Client: -
‘ GET /authorize?
response_type=id_token%20token
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&scope=openid%20profile
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com ‘
Also, find the below example of the authorization request sent in the browser URL using nonce as a parameter: -
‘ https://${yourDomain}/oauth2/default/v1/authorize?client_id=0oabv6kx4qq6
h1U5l0h7&response_type=id_token
token&scope=openid&redirect_uri=https%3A%2F%2Fwww.example.com&state=state-
296bc9a0-a2a2-4a57-be1a-d0e2fd9bb601&nonce=foo ‘
In my NodeJs application im using jwt to manage the user session, inside a jwt token i store user_role and user_id. This is my route:
routes.post('/manga/post', Authorize("Scan"), MangaMiddleware.valid_manga_store, MangaController.store);
In the middleware Authorize("Scan") I verify the jwt token with "jwt.verify", if its valid i going to check if there is a active user with the token id and if his permission allow him to access this route, if so i use next()
In MangaController.store i going to save a new manga, and i need to save in the document the user_id who made the request.
That's my point, i already decoded the token in Authorize middleware but the decoded data do not persist out of the middleware. To access the user_id from MangaController i have to verify the token again.
I think i should avoid verify the same token twice, so in the middleware Authorize after verifying i was saving the user_id (encrypted) inside req.auth and after use it in the controller, i was setting req.auth = null. This way the user_id is stored in req.auth for a short period of time.
req.auth = user_id //after encrypting
My friend told me this is a bad idea storing decoded data inside req parameters, but i don't think it is this bad.
In a nutshell. Do i need to verify the token twice? Is there another way to retrieve this data? It is that bad storing decoded data in req parameters? I do appreciate your time and help.
Verifying and decoding JWT are two different things. When you verify, it's checking for its integrity, ie making sure it has not been tampered with, while decoding JWT means converting from base64 to readable format (UTF-8?). So it doesn't have to be verified twice.
Assuming you sent your token in headers as "token":"base64encodedJwt", then after successful verification, whenever you need user_id, you can then simply decode the JWT. Use some JWT decode library.
let token = req.get('token') || req.headers['token'];
let payload = decodeJWT(token);
let userId = payload.user_id;
If you are not storing it in req object, then you will have to decode it everytime you need it. So req.auth = userId should be fine.
We are using Azure active directory Oauth code flow to authenticate the user.
We got the access_token, id_token and refresh_token using code(got it on redirect URL).
We are using id_token to authorization each request after successful authentication and we can verify JWT using the public key which we got from /discovery/v2.0/keys api.
Now, JWT will expire after 1 hour. so we need to refresh this id_token.
I am refreshing id_token using below cURL
curl --request POST \
--url https://login.microsoftonline.com/{tenant_id}/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'client_id=client%20id&refresh_token=refesh%20token%20&grant_type=refresh_token&client_secret=client_secret&scope=openid
In the response of this API, we got the access_token, refresh_token, id_token, but if you observe id_token, it does not contain JWT signature (the third part of JWT), without signature we can not verify JWT
We can not find any document reference why id_token is not having a signature part.
Is there any other way to refresh id_token?
Is there any workaround if id_token can not be refreshed?
In some cases an Id token may be returned without a signature, especially if it is acquired through a back-channel with a client secret.
You already are getting the token through an encrypted channel, from the authority.
If someone was able to inject something there, they would be able to direct your app's requests for OpenID metadata as well, replacing the signing keys your app expects.
Thus the signature would not add much value here.
In addition, you won't send the Id token to any API as Id tokens should not be used for authorization.
That's what access tokens are for :)
The OpenID Connect spec has this to say: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.
But then, interestingly mentions this as well: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
ID Tokens MUST be signed using JWS and optionally both signed and then encrypted using JWS and JWE respectively, thereby providing authentication, integrity, non-repudiation, and optionally, confidentiality, per Section 16.14. If the ID Token is encrypted, it MUST be signed then encrypted, with the result being a Nested JWT, as defined in [JWT]. ID Tokens MUST NOT use none as the alg value unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow) and the Client explicitly requested the use of none at Registration time.
So.. it could be that Azure AD is not compliant with spec?
EDIT: The v1 endpoint of Azure AD is not compliant in this regard. The newer v2 endpoint is fully OpenID Connect compliant.
I have created my protected routes and i will like to access the protected routes using jwt token from postman
One way to get around this is this:
Store JWT in session/cookie for the user.
Send this as a request header. You can call it x-api-token or whatever you like.
Keep the public key for JWT in server's environment or file-system.
Read the value of header i.e. x-api-key
Verify using any JWT library to make sure it's authentic.
As the title suggests, where are JWT tokens stored on the server side? in database or in memeory? I understand the implementation can vary due to different requirements, but just in general where would you store it?
If I want to provide a very basic token authentication server, meaning upon receiving a username and password via a POST request, I would like to return a token. In this case, how is a token generated with a very basic algorithm work differently than a jwt token?
With a token generated by a simple algorithm:
it does not contain payload
its value is not computed based on the username and password, thus it cannot be rehashed back to anything meaningful
In this case, is there still value to use JWT?
Thanks!
client needs to store it, on server storage is not required.
JWT have all the claims in itself and is signed by the server as well. On receipt, server checks for the signature and reads the claims. It does not match it against a stored value. That is the whole point of using JWT against access tokens.
Look at how a JWT is structured.
You don't need to store token on server side.
You should store a private key ( any string of your choice)at server preferably as environment variable.The jsonwebtoken provided method use this private key to generate a token to pass to client.
Client has to store this token at client side so that it can pass this token to subsequent request to server in header.
Server would extract the token value from header and validate it using private key by calling a method of jsonwebtoken.If token is not modified by any means then validate will succeed.
Jwt token is not required to be stored but the "secret-key" needs to be stored.
The structure of jwt is header.payload.signature where signature is generated as below by the server :
signature = HS256(base64Header + '.' + base64Payload, 'mysecret')
So in essense:
1.header.payload.signature is sent to client on first sign in
2.client return back header.payload.signature in subsequent api call
3.server decodes it for verification as below:
base64Header, base64Payload, signature = token.split('.')
header = base64Decode(base64Header)
payload = base64Decode(base64Payload)
serverComputedSignature = HS256(base64Header + '.' + base64Payload,
'mysecret')
if serverComputedSignature != signature:
print('FAILED')
A token is a generic term. JWT defines the structure of a token which contains the below three parts.
1. header
2. payload
3. signature
Storing JWT or any other format of token is driven by the business need.
If the content of the JWT has to be used/validated for any reason then it can be stored in a DB or any other storage.
If the need is to validate the signature then there is no reason to store the issued JWT.