i am trying to implement jwt on my django app but i have some confusion
when i make post request on postman with email pass:
http:www.127.0.0.1:8000/token/
i get refresh and access token:
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU3NDUwMTcxNSwianRpIjoiNDg5YjjZmQyY2IwNDI4YjgxMzg4NDU1YmQ1ZGM3NDYiLCJ1c2VyX2lkIjo2fQ.5Bms8FiqOdlIeyi1k1cRcfLC1qmHEH05MysZnzMcKCA",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTc0NDE1NjE1LCJqdGkiOiI1OTBkMGjZjJlYmE0YjNmOTE1MzI5NTEyOGExNzUyMCIsInVzZXJfaWQiOjZ9.7HZYpD-mCp5li4PnGSuwQGyVa7nsDYvUVWaxdyKYk-E"
}
and when i make this:
http:www.127.0.0.1:8000/rest-auth/login/
i get access token:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo2LCJ1c2VybmFtZSI6ImFrYXNAbWFpbC5jb20iLCJleHAiOjE1NzQ0MTU4NTYsImVtYWlsIjoiYWthc0BtYWlsLmNvbSIsIm9yaWdfaWF0IjoxNTc0NDE1Nzk2fQ.DEpZNq-kFFqYb3ZfAiYDB1CigfY36qpS9o-T7rJ5-_I",
"user": {
"email": "akas#mail.com",
"password": "pbkdf2_sha256$150000$OdHDeKGCViax$BvOXGFheSJoNb692ZVYxoWnZxK2xZQpvbu7HA/SC5Po="
}
}
then i can make get request when i add this access token in header authorization
i don't understand whats the difference between these two access token?
Your first pair of tokens aren't valid, and they're structurally extremely different from your second token.
A JWT has three parts, separated by periods. (RFC 7519 has the full specification.) The first part is a header; the third part is a signature; but the middle part is a set of claims that's really the interesting content of the token. The first two parts are just base64 encoded so you can just decode them to see what's inside. The claims of your first access token look like
{"token_type":"access","exp":1574415615,"jti":"590d0hٌ?X?M?َLML̎MLL?LM?L?\?\???
but the second one is
{"user_id":6,"username":"akas#mail.com","exp":1574415856,"email":"akas#mail.com","orig_iat":1574415796}
This suggests to me that you have two different JWT implementations in your application and also that one of them is configured wrong; since the first token can't be decoded as JSON it can't be validly used.
There's one other interesting thing that may be a hint when debugging. If I take your access token and copy it into the decoder on the https://jwt.io/ front page, and I delete the characters jZj in the middle of the token, then I get
{
"token_type": "access",
"exp": 1574415615,
"jti": "590d0beba4b3f9153295128a17520",
"user_id": 6
}
which (up to the signature) could potentially work. The different claims between the two tokens still look odd, though.
("jti" is a standard claim for a unique identifier for the token; the most useful application of it is keeping a blacklist of revoked tokens. There's also a standard "sub" claim identifying the subject of a token which would probably take the place of your "user_id".)
Related
My website supports Sign In with Apple.
In the configurations of this service, I have an endpoint here:
What I receive in this endpoint is a JSON like this:
"{"payload":"eyJraW...................NLnyA"}
However, I don't find absolutely anywhere how to decrypt/decode this payload...
The "Learn more" link sends me here: https://developer.apple.com/help/account/configure-app-capabilities/about-sign-in-with-apple
The page below this one is this: https://developer.apple.com/help/account/configure-app-capabilities/enabling-server-to-server-notifications
Nowhere I see how to interpret these messages...
Does anyone know what do I need to do to read these payloads?
It looks like the general procedure for Server-to-Server notifications are outlined here. This is what the docs have to say:
These notifications contain a cryptographically signed payload, in JSON Web Signature (JWS) format, signed by Apple’s private key. After your server receives a notification, examine the JWS payload and use the algorithm specified in the header’s alg parameter to validate the signature. For more information, see Fetch Apple’s public key for verifying token signature.
So, this payload is really just a JWT (verify/decode with the JWT library of your choice, there are many to choose from). Because anyone can access your endpoint, you need to verify that the token is really from Apple. Note: do not try to decode the JWT yourself. Because of security concerns, it is better to let a library do it for you.
After validating the token signature, your server performs work according to the type value in the events claim of the token. The notification payload object contains information about user-initiated account modification events.
The decoded JWT will contain something like this (example is from the docs):
{
"iss": "https://appleid.apple.com",
"aud": "com.mytest.app",
"iat": 1508184845,
"jti": "abede...67890",
"events": {
"type": "email-enabled",
"sub": "820417.faa325acbc78e1be1668ba852d492d8a.0219",
"email": "ep9ks2tnph#privaterelay.appleid.com",
"is_private_email": "true"
"event_time": 1508184845
}
}
events.type has the event that happened (full list is here), and the rest of the token contains everything else you'll need.
#Michael M.'s answer helped me understanding that this payload is basically a JWT.
This is what we need to do (minimal example):
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
$json = json_decode(file_get_contents('php://input'));
$publicKeys = json_decode(file_get_contents('https://appleid.apple.com/auth/keys'), true);
$decodedPayload = JWT::decode($json->payload, JWK::parseKeySet($publicKeys));
var_dump($decodedPayload);
This is my Service for generating JWTs in my Project. This, works, a user can login, retrieve a JWT and do operations with this token until its expires.
#Singleton
public class JwtService {
public String generateUserJwt() {
return generateJsonWebToken(Set.of(Role.USER));
}
public String generateAdminJwt() {
return generateJsonWebToken(Set.of(Role.ADMIN));
}
public String generateSuperAdminJwt() {
return generateJsonWebToken(Set.of(Role.USER, Role.ADMIN));
}
private String generateJsonWebToken(Set<Role> roles) {
Set<String> groups = Set.of(roles.stream().map(Role::getValue).toArray(String[]::new));
return Jwt.issuer("https://example.com")
.subject("myproject-2022-jwt")
.upn("myproject-2022-jwt")
.claim(Claims.birthdate.name(), "1985-10-25")
.groups(groups)
.expiresAt(System.currentTimeMillis() + 3600)
.sign();
}
}
Problem
Let say a User login, 10 seconds later I ban/delete his account. His JWT is still valid and he can do requests with postman using last JWT.
How I can handle this?
You can't.
The entire purpose of a JWT is to be self sustained and independent. This is why its never recommended to expose JWTs to external clients. Even though people do this all the time.
The rfc for JWTs states the following:
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. [...] enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.
In this context, "claim" can be something like a 'command', a one-time authorization, or basically any other scenario that you can word as:
Hello Server B, Server A told me that I could , and here's the (cryptographic) proof.
This is why you need to have short lived JWT that are only valid for minutes. Because if one gets compromised you can't block/logout that user.
OWASP mentions this in their cheat sheet series, and their solution for mitigation is to implement a block list, but remember that once you do that, the entire solution is not stateless anymore, and you need to share this block list over multiple servers.
Which basically means you can use cookie sessions, as they have more protection and fulfills the same purpose.
Using JWTs as session bearers has always been a bad idea and has been mentioned over and over:
Even back in 2016 it was not advised:
Stop using JWT for sessions part 1
Stop using JWT for sessions part 2
Redis blog:
JSON Web Tokens (JWT) are Dangerous for User Sessions
Okta blog:
Why JWTs suck as user sessions
I am playing around with building a custom Oauth2/OpenID library, and is having thoughts about validating the tokens.
I am using only JWT for all token types (Access, Refresh & ID), but I am thinking; How would the resource server validate ex. the access token, and make sure it is only access tokens from the issuer being accepted, and not refresh or ID tokens, since they would also be valid, hence they come from the same trusted issuer?
Likewise, how would make sure, the token sent with a refresh grant, is not just an valid access token, since it would also be verified...
I know an easy fix would be just making a custom claim, describing what kind of token it is, or using different signatures for each, but is there a "right" way of doing it?
One way to separate the ID token from the Access token is by looking at the typ claim in the JWT-header.
Some IdentityProviders uses the at+jwt typ to indicate that the token is an access token that follows certain rules. But this is not a mandatory thing to follow.
{
"typ":"at+JWT",
"alg":"RS256",
"kid":"RjEwOwOA"
}
Otherwise they can look at the claims inside the token to determine if it is an access or ID-token. The token-signature itself can't be used to determine the token type.
You can read more about the standard for access token here and here
Refresh and reference tokens are typically not in a JWT format, instead they are more like a random string.
based on the documentation the validation response looks like this
{
"success": true|false,
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string, // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...] // optional
}
I wonder whats the purpose of the timestamp field in the response. Do I need to validate it?
I assume each validation token can only be used once and they expire after some time. So I shouldn't have to worry about the token reuse problem. I can't think of any exploit one could do even if the token doesn't expire at all.
The same goes with hostname. Since the site-key and site-secret must match so I shouldn't have to validate that field either.
Do they exist only for the purpose of logging?
The documentation for the session token for the Google Places API refers to the parameter as both sessiontoken and session_token throughout the document. Which one is correct?
Making a request with both sessiontoken and session_token parameters included results in:
{
"error_message": "Invalid request. Only one of the 'sessiontoken' or 'session_token' parameters are allowed.",
"predictions": [],
"status": "INVALID_REQUEST"
}
So apparently either one is acceptable.