Cross-Domain link authentication using JWT - security

I have a link that contains a parameter token which is the JWT token that will be validated across another domain. I'm struggling with the fact that a user can copy and share that link across several browsers or with other users.
The jwt payload looks like the following:
{
"userId": "46",
"role": "User",
"nbf": 1589877059,
"exp": 1589963459,
"iat": 1589877059
}
My goal is to secure that link from being shared other than the current user while authenticating that user on the second domain.
Am i missing something or is there any other way to secure a link across different domains? Any suggestion is really appreciated.
Update
An approach I'm trying is storing the last active SessionId in the database and validating it on both sides. In case the token is valid and actual SessionId is different from the last active id, then redirect to some unauthorized page. but the drawback is that the user will require session-authentication instead of cookie authentication since the session will reset each time the user closes the browser but the cookie will remain the same.

Related

Oauth2 : how and where to store client id and secret

I have an authorization server and my client is an angular app.I'm not a third party app.
I used this symfony bundle https://github.com/trikoder/oauth2-bundle
I'm using grant type password.
{ "grant_type":"password", "client_id":"myclientid", "username":"john#doe.com", "password":"foo", "client_secret":"3d4a940.....3c1ea38b5" }
And the response is :
{ "token_type": "Bearer", "expires_in": 60, "access_token": "eyJ0eXAi....nK0Ag", "refresh_token": "def50200dfce4da3....fdc689e5" }
The access_token is only valid for 1 min, afterward the client need to use the refresh token to be able to talk to my api :
{ "grant_type":"refresh_token", "client_id":"myclientid", "client_secret":"3d4a940.....3c1ea38b5" "refresh_token": "def50200dfce4da3....fdc689e5" }
client_id and client_secret are stored in a table.
My question is :
Is it safe/recommended to store the client_id and the client_secret in the local storage of the front angular app ? Because it basically represents the user credentials and if some one steal them they would have access to the api. But without them the client can't send request to the api.
I crawled the web but I can't find a real answer, even on the oauth 2 documentation
Thanks
A few points here:
Your angular app should use the authorization code flow + open id connect
Consider using a more standard authorization server and more standard access token lifetimes
Session storage has fewer issues around Safari / Firefox and SPA restarts
Whether to use session storage for tokens depends on data sensitivity + risk analysis
Consider that the session time for which access tokens are valid sometimes maps to a user consent
I have a write-up, which is based around trade offs between usability and security: https://authguidance.com/2019/09/08/ui-token-management/

How to generate a refresh token?

I am implementing JWT in one of my node apps. I am wondering, if there is any definite format/ structure in which a refresh token should be generated?
By definite format I mean whether a refresh token contain any claims like a JWT?
UPDATE
Let's assume a refresh token to be: fdb8fdbecf1d03ce5e6125c067733c0d51de209c (taken from Auth0). Now, what am I supposed to understand from this?
Is this a random unique string?
Is this an encrypted string which has claims inside?
Short answer
A refresh-token is just a random string.
All the user-related information including claims go in access-tokens
Explanation
You should keep something like this:
{
_id: [refreshTokenId],
value: 'fdb8fdbecf1d03ce5e6125c067733c0d51de209c',
userId: [userId],
expires: [some date],
createdByIp: [some ip],
createdAt: [some date],
replacedBy: [anotherRefreshTokenId],
revokedByIp: [some other ip],
revokedBy: [some other date],
}
Refresh tokens are random strings generated by the authentication server. They are generated after successful authentication (for example, if the username and password of the user are valid).
Their sole purpose is to remove the need to exchange user credentials repeatedly. They are different from access-tokens.
An access-token usually has information about the user (like name, claims). These are usually short-lived. JWT is one example.
To get a JWT the app has to verify the credentials.
To add additional security, and to stop bothering the user for username and password every 15 mins, we just create a signature on the server-side and forward it to the app.
Next time, whenever the app needs to create a JWT, it can just send the signature back to the server. This signature is your refresh token.
Refresh tokens are also supposed to be saved somewhere.
So you would probably create a table/collection in your database, linking the refresh-token values with userIds and ip_address.
This is how you could create a session management panel for the user. The user can then view all the devices (ip_addresses) for which we have registered a refreshtoken.

How to create a JWT that contains the Auth0 User_Metadata

So I know how to create tokens and how to read tokens but I am running into an issue with getting the User_Metadata from the Users I created in Auth0 (without login them in from my application).
What I am trying to do is this:
User some where with a device logs into Auth0 and generates a JWT
Token
User now calls my API and passes Bearer with token in header
I read Bearer and Authenticate that the token is good. I then want to
pull the user information from the token to use to make sure they
have rights to do something.
I am not wanting a 2nd database that holds user information that they will need to log into my API so I know who they are. I just want to be able to use the JWT Token to get that information. Right now when I create a token I have this in the Payload:
{
"iss": "https://.....",
"sub": "RTMLeICuyL1kyeQN#clients",
"aud": "https://.....",
"exp": 1494031764,
"iat": 1493945364,
"scope": ""
}
If I go to Auth0 User Details tab I can see the user and the user_metadata and app_metadata that I want to return but not sure how to get it. Thanks for any help.
I was not able to get the User Profile data from Auth0 to come in on the JWT Token but I was able to use the client scopes in Auth0 to create the scopes needed to do Authorization. This is still not the best answer but it will allow me to determine if someone has rights to view that object and records.
I will go into more details as I write up an example.

OAuth: why principal id is different when authenticated in Browser and WinPhone App

I am trying to use Google OAuth authentication for Mobile App hosted in Azure, but getting user ID (SID) in different formats.
When I access the API from browser directly, I'm redirected to Google login page, and after authentication the next request to my API comes with the headers:
"x-ms-client-principal-name":"pavlolissovtest#gmail.com",
"x-ms-client-principal-id":"108491597139717511334",
"x-ms-client-principal-idp":"google",
"x-ms-token-google-access-token":"ya29.Ci9-A-oE8p4vVelYhRKqjMKY6KGxeW4OtXT-KGtBO3AxsiBqiCawn8sxL-qg4msWrw"
In Windows Phone App (authentication with WindowsAzure.MobileServices.MobileServicesClient), when logged with the same account, request comes with different headers:
"x-ms-client-principal-id":"sid:3fc89f071b7cb8f18919614ac46d3636",
"x-ms-client-principal-idp":"google",
"x-ms-token-google-access-token":"ya29.Ci9-AxC3kfrYrV8ssLUkbwFJJYDPsklsUH7r3HG0f6KB_wWzXV9AqE_wGPASiYxcWQ"
So now I have different principal ids for the same user account.
If now I call https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=, for both tokens I get the same result:
{
"azp": "1083509260178-cntp3794bggcs5dtkse0mtbvpqigoa78.apps.googleusercontent.com",
"aud": "1083509260178-cntp3794bggcs5dtkse0mtbvpqigoa78.apps.googleusercontent.com",
"sub": "108491597139717511334",
"scope": "https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"exp": "1476643317",
"expires_in": "3161",
"email": "pavlolissovtest#gmail.com",
"email_verified": "true",
"access_type": "online"
}
This allows me to identify the user whatewer login option is used, but is it really correct to call googleapis for each request? What is the proper way of identifying the user from headers, or maybe converting one value into another?
And what is the meaning of having these values different?
Thanks for your advice!

REST | JWT | Auth: How To Verify Authorities For Secure Resources

Token-Based Authentication: JWT? Check. GET /items/:id... How?
This is a small question, but probably a big answer, as I'm a bit new to this...
Once I have provided a client a JWT -- and they wish to obtain a resource -- what does the logic-flow of verifying Client look like?
In other words, I have a JWT payload such as...
{
...
"sub": user.id
...
}
... and Client needs to access item 998 at /api/items/:id...
My current approach looks something like the following.
// ItemsController.lang | 'GET /api/items/:id'
var userId = jwt.decode(token).sub;
var isValid = checkUserIdInDatabase(userId);
var secureResource = ORM.findOne({ user: userId, id: request.itemId });
response.send(secureResource);
Along with this, when Client signs up/in, I provide them a response which looks like this...
{ user: { id: 998, email: 'no#username.com', preferences: [...] }, jwt: token }
Should I ever be sending id & email if I'm issuing a JWT?
Given that I should have middleware to check if my jwt.sub's [userId] value exists in the database, should I use this userId as part of my query, or should Client be sending Server the userId as request.body.userId since it obtains it upon sign in/up?
Is it a no-no to assign a userId to payload.sub?
Do I need to generate a new JWT with a new lifespan upon every request and send it to the client?
What are all my security blunders, what is best practice, and what would you do?
Every tutorial I look at shows a nice & clean high-level flow stating [simply] that 'if the JWT is verified, the resource is sent to the client'.
Can you please provide me with some direction on how all this token-based authentication stuff is supposed to work at the low-level -- namely, in order to request secure resources?
PreThanks,
Cody
This is solely my point of view and i am no expert, here it goes:
1) I think you should not send user ID in your response as there is not a lot of scenarios where i see that would be necessary for client to know its user id, you easily assign this to your token payload and use a middle ware like express-jwt
to do the decoding and giving the user id for you.
2) Do not rely on sensitive data sent by client, if you use express-jwt then it would assign user id with every request object eg: req.user.userId
3) you can assign user id and other small user session data in your payload, your client would require your secret key and to be able to decode that information , always have a strong secret key.
4) I think you should have token life span expire after a day or even less, there are scenarios where you may need to go longer i think 1 week should be maximum amount of time you should have your token life span. now you can always refresh your token and have your application check after some interval of time if its token is valid and request for refresh or new one after expiration .
5) may be these:
Have a strong secret key.
Use cookies to store secret key for web applications
Keep your token life span short as possible.
Use HTTPS protocol for APIs.
Write a middle-ware or use already existing middle-wares for user authentication. eg: express-jwt
jwt tutorial tutorial2 ,using storm-path and using passport
Hopefully this helps.

Resources