I am totally new in JWT implementation and an issue came up.
I have built a user login authentication with JWT in php. On user login, if user's credentials are valid then response of login API is a token which is stored as a cookie and instead of having $_SESSION variables, I get user's data by making an API call to decode token and retrieve user's data on every page of web application.
If user wants to update his personal details (name, e-mail etc) I want to generate a new JWT based on new details and to force previous one to expire or somehow make it invalid. So, in future API calls previous token must be invalid.
I thought of storing tokens on database but this is not right I suppose.
How can I make it works?
Stateless authentication (in this case JWT) stores the user session data on the client side (browser).
The data is signed by the key of IdP to ensure the integrity and authority of the session data.
Since the user session is stored on the client side, the server only have the capability to verify its validity by checking whether the payload and the signature match.
One of the disadvantages is that you cannot revoke the session anytime: since the user session is stored at client side, the server does not have any rights to delete the session.
• What you can do:
You can remove the stored JWT on the client and put this in a db blacklist and check everytime someone calls the APIs
You cannot without making the api stateful.
So either you store a reference to the JWT in your database and delete it or you could blacklist the revoked tokens and check on authorization if the token was blacklisted and therefore is revoked.
You can do two things:
First delete the old JWT token and insert new one.
Or create an field (is_expired) in database to check the status of token and default should be false so when you create new one, it marked to true and the old one must change with false value.
Related
I would really like some opinions on whether the following is a safe method as user authentication, and if not, please point out it's shortcomings.
React front end
PHP / MySQL based RESTful API on remote server
1) user signs up, data is posted to the API, user is emailed a single use activation link to ensure email is valid before they can access their account.
2) user signs in, API validates the data in all of the usual ways and then sends back a JSON object containing their user ID and an access token.
3) user ID and access token are set in localStorage on the users device upon receiving the data. React then grabs that data from localStorage and uses it to set and control the state in Redux stores providing an App wide Auth state.
4) user ID and access token are sent along with every future request made to the API. In the instances where a user isn't logged in, i.e - they don't supply a valid user id with matching token, they are automatically prevented from requesting anything that requires authentication at the very first entry point of the API. Suitable responses are sent back which in turn update the front end state to reflect a non-logged in user.
5) When the user logs out the access Token is deleted from localStorage.
A bit more detail about some the inner workings :
All tokens are generated server side and stored in the DB, they are random and unique bin2hex(random_bytes(32)) and only valid when supplied with the matching user ID. So changing the user ID in a request will result in a failed auth response, as will supplying a valid user ID with a mismatching or expired token.
Tokens are single use and a new token is generated, stored and then sent back in the response from every authenticated request along with the corresponding user ID. This may be overkill and put a lot of extra strain on the server. Would really like your opinions on this aspect especially please.
Tokens are set to expire in 2hrs regardless. So if the user leaves themselves logged in, they will be automatically logged out after 2hrs of inactivity.
User ID and Token are sent as part of the JSON body of every request (not in the headers). Is this a cause for concern?
At no point (other than sign up and login) is the users password transmitted or stored in localStorage or used by the React frontend. A matching user ID and Token is all that is required to validate the user after the initial authorization.
All connections are made via HTTPS.
Can you spot any glaring security risks in this approach? Am I missing the elephant in the room here?
Obviously the user ID and matching token is as good as supplying the users email and password on every request as far as auth goes, but I can't use PHP sessions or cookies* as the API is hosted on a different domain. This is the best workaround I could come up with without having to go down the JWT or Oauth route.
How flawed it could be in regards to how I am checking and validating data on the API can't be practically addressed here, but assuming that it is all being done correctly is this method secure enough in principle?
I look forward to and thank you in advance for your opinions :)
*without a ton of workarounds which would ultimately be superflous as this App can only be used with modern browsers which all support localStorage.
In my opinion is not save to store the token in the local store,
As said in https://auth0.com/docs/security/store-tokens
Since Browser local storage (or session storage) is not secure. Any data stored there may be vulnerable to cross-site scripting. If an attacker steals a token, they can gain access to and make requests to your API. Treat tokens like credit card numbers or passwords: don’t store them in local storage.
A better option is to use cookies since they are managed by the browser.
I need to implement centralised authentication server with single sign on.
One of the requirements are, that there should be no intermediate login screen (a.k.a direct login from service provider), so OAuth2 with password grant seems like the best option here.
User is read-only, authentication is used only to access specific content, which is the same for all users, the users can't change their personal data or anything else. We use user ID as an username and date of birthday as a password, it's not really secure, but that's not something we can control, because we get credentials from other 3rd party service, though we still want to make everything secure as possible, because user data includes such personal data as full name and home address.
To make it clear, next I will describe how I imagine OAuth2 and SSO flow to work together:
User enters his credentials and submits the login form in service provider
Service provider (SP) sends a request to identity provider (IdP), to check if credentials are valid (Request is signed with client id and secret as a base64 bearer token: base64(client_id:secret))
If credentials are valid, IdP creates access token (5min) and refresh token (24h) and returns them to SP
On every user request, SP uses access token to receive user data from IdP
If token is expired, SP makes another request with refresh token to retrieve new access token. Request must be signed with client id and secret.
So it's pretty much, how OAuth2 password grant would work, probably hardest part is to make it work with SSO, I couldn't really find any working stateless implementations, so came up with this:
When access and refresh tokens are issued, IdP stores refresh token in a cookie.
When user visits SP for the first time, quick redirect to IdP is made, if refresh token exists in a cookie it’s added as query param to the redirect url and user is redirected back to SP. If no, some query param is added to identify, that user is not logged in, to avoid redirect loop.
SP uses retrieved refresh token to issue new access token (which is unique for every SP).
So access token can be used only by service provider, which it was issued for. And refresh token, can be used by all service providers, but to issue new access token client id and secret must be provided, so refresh token alone is useless.
Also forgot to mention that all websites use TLS.
What do you think about this implementation, is it secure enough? Maybe you have other suggestions?
I am authenticating users to consume my own API (so a trusted source). What I am struggling to identify is where is the best place to store the return access_token on the client side? Do I create a cookie, or save the data in localstorage?
Also should I only store the access_token, I should I record the refresh_token? What is the refresh token used for?
It is safer if you only store the access token on the client side even if your refresh token expires after a certain period of time although doing this decreases the possible attack window.
This is one way of doing it (if you want to store access & refresh tokens):
https://stackoverflow.com/a/18392908/5549377
However there is another way of doing it.
In this way, the client will only get the access token and refresh token is completely hidden from the user. But inorder to do this, the access token as well as the refresh token should be stored in the server side. The best place is in the database. This raises the obvious question: security? Well the answer to that is you can always encrypt the data that is being store in the database and secure your database as much as possible.
Create a table (user_token table) that can store the user_id, access token, refresh_token and even the session_id.
In every login check if a record is existing under the user_id in the user_token table. If it does not exist, request the oauth/token and store the access and the refresh token in the user_token table.
After the login is successful, you can write a .run function in your angular to request for the access token for the user. (remember in the user_token table we had a "user_id" column. Hence you can request filter the current logged in user from the Auth::id() function in laravel.
Once the access token is found, the server should return the access token and access token only to the client.
After the client received the access token, you can do a handshake call to the route which is protected under 'middleware' => 'auth:api' by adding the recieved access_token to the header like this :$http.defaults.headers.common.Authorization = 'Bearer ' + data.access_token;. Also after doing that make sure you add the same token to the a rootscope variable like this:$rootScope.accesstoken = data.access_token;
If the handshake call is successful, then you can add valid access token from the rootscope to an angular cookie like this : $cookies.put('access_token', $rootScope.accesstoken);
If the handshake call is not successful, you can request a new token. To request a new token, use a new route that will redirect to a seperate function. This function will fetch the refresh token under the user_id of the current user and request a new access token from the oAuth end point (refer Passport API docs). Once you do this update the record under the user in the 'user_tokens' table and return the new access token to the web client. On the webclient side, store the recieved token in the angular cookie like this: $cookies.put('access_token', $rootScope.accesstoken); and add that same token to the http headers liek this: $http.defaults.headers.common.Authorization = 'Bearer ' + data.access_token;
By the way why did I mention that I should store the token in the angular cookie. Well if you store it only on the rootscope, if the page refreshes, the app will have to request for a token again because whatever the data in the angular rootscope is lost after refresh. But in the angular cookie, it is not. hence this is why I suggested to add to the angular cookie.
Very important:
For every ajax request you make, if the request fails under the code 401 (unauthorized access), you should call a request new token function from angular to Laravel's request new token function. And once it is successful, insert that new token to the http header and the angular cookie as I mentioned.
Note:
The point of the refresh token is to verify that you are the authenticated user for the old access token (let's call the token xxx).
You can use the access token as long as it expires. Once it does you need to tell the server that you cannot been using this access_token xxx and it is expired now, so give me a new token. When you make this request (to give you a new token) the server should know you are the legitimate user of the previous access token, so the server will ask you to prove that you are legitimate. At that time, you can to present the refresh token and prove the server that you are legitimate. This is the use of the refresh token.
So how will the server verify you are legitimate by the refresh token?
initially when you requested the access token, you are given the refresh token so in that case the server will know.
I suggest you read and learn more on OAuth 2.0.
I recently went through some client-side options for token storage so I'll refer you the answer provided in: Where to save a JWT in a browser-based application.
Long story short, both cookies and Web storage are suitable options for storing access tokens and the right choice depends on your exact scenario.
In relation to what you should store, it's usually just the access token mostly because refresh tokens are not typically issued to browser-based applications because they are long-lived credentials meaning the time available for someone trying to steal them is highly increased and the browser storage options all have their deficiencies.
The refresh token is also of particular interest when a client application wants to have access to a protected resourced owned by the end-user even when the user is not interacting with the application; usually referred to as offline access. Most scenarios for browser based applications still imply that the user is online so lack of refresh tokens is not that a big of a deal.
Hi I am creating mobile native application that uses REST API endpoints to communicate with server side.
I have had previous experience developing native clients, but I have simple token (random generated string) stored in DB in the same table where user information is stored. So it is like sessions used in browser, but instead of cookies each request has token in the header.
Recently I discoreved JWT token. It seems to be great way to secure endpoints which are private. You can request token from mobile client providing you pass + login and get generated token in response.
But the one important thing is that this token is not stored anywhere on the server, server verifies the token using secret word, which is private for the server like private key.
That's okay for secured endpoints, but what to do if I require user session, for example how do apps like Facebook, Amazon, Aliexpress ... work, they have ability to use the app without providing credentials, just navigating through the store, but require logining in when user want't to make purchase. And after that user session is kept for some time.
This can be implemented with the JWT token without any problems, but when user need to logout, what to do in this case ? Token is not stored anywhere on the server, so how can I destroy this token, to make it invalid ?
If token is stored in the database, API is not stateless, as REST API should be.
So in general there is no way to keep user logged in in stateless API, am I right ?
I have some ideas how to implement this using JWT token, but again this will not be stateless API, as I understand.
Create the list of expired tokens
Store JWT token in the database, but what is the purpose of self descriptive token (JWT) in this case if it is stored in the database, the main idea of JWT token to keep all information with token, as I know.
Please suggest what is the best way will be in this case, and correct me if I have mistaken.
Thanks.
If you're using JWTs, then you can't have a server side state in order to properly logout the user without defeating the purpose of using JWTs in the first place. The best option though if you want to do this is to have a last logout date stored in the DB and in the JWT, and if these don't match you logout the user (without updating the date in this case). However, you now have server side state.
Storing logged out tokens in the DB seems like overkill though.
An alternative option is that you could generate a 128 bit token generated by a CSPRNG, store this using SHA-256 in the database, and then use the unhashed value in a web token. This way you can simply delete the entry in order to logout the user server side. This is the more secure option as you now have a way to properly expire tokens and sessions on the server. If a user changes their password, or wants to secure their account by logging out other sessions you now have a way to do this.
JWT authentication is basically happens on both the client side and server side.
When the user sends Username and password to authenticate. its checked against the db and if valid a joken is generated and sent back to the user. There are multipe API's for generating the JWT token, you can check out http://jwt.io/
Once the token is generated and sent back, it needs to be sent along with header in each request and needs to be validated, on the server side, before serving the API back to the user.
There is no need to store the the token as the API itself will allow you to decode it on the server side.
How i am doing it:
I generate a random id (I call it validation code) and store it in database when user signup, encode it in jwt.
Whenever any request is made with jwt, I check the validation code, if it is correct: access is granted.
To expire the session like after changing password, I change the validation code in DB.
If you need to logout a user, provide a logout link. The server should reset the session data by encoding the token with any empty array for example. The user will have a valid session but will not have the valid information to validated them.
Valid Token at login
$data = array("id"=>1,"user_type"=>"Admin");
$token = JWT:encode($data, $key);
Validating Token
$token = $_POST['token'];
$data = JWT:decode($data, $key, $hash);
if($data.id){
return "valid token";
}else{
return "invalid token"
}
I've implemented the oAuth in php (currently for twitter) and as I've read in several tutorials you should store the access token in db for future use. However I don't see how you know if you have the access token stored for a particular user to decide if you should pull it out of the db or regenerate it. Here's a flow describing my question:
First time user signs in:
get request token
send user to provider's authentication page
user returns to callback url with oauth token and oauth verifier
get access token
save access token/user_id/screen_name on db for future use
User returns 10 minutes later:
access token is still in server session vars if user didn't log out. else, repeat process.
User returns 1 month later:
get request token
send user to provider's authentication page
user returns to callback url with oauth token and oauth verifier
( at this point I only have oauth tokens, how can I know if the user has previously logged in with twitter and pull their access token from db? )
if it is the user's first loggin, generate access token.
The main workflow for oAuth is clear, however it is not clear how to handle returning users and which data should be stored or not.
A million thanks!
You should not regenerate token for each access. Generate it only when it's expired. I've build twitter application using OAuth. Here my flow:
when user login, I will check if they have token in DB
1.1. If it's not exists, authenticate them and then store and use the resulting token
1.2. If it's exists, use it.
1.2.1. If twitter doesn't complain, then the token still valid, use it.
1.2.2. If twitter complained, then the token is expired. Return to 1.1.
1.2.3. If after x retry twitter still complained. Something wrong, notify admin!
Here's the graphical explanation:
The only thing I believe is missing here, is generate a random (long and unguessable) user id first time the user joins the system, and store it forever. this way you can tell who's taking the actions