I'm working on authentication on spring framework using JWT, bearer token.
public String generateToken(UserProfile authentication) {
// set the expiration time
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
// Generate token and return
return Jwts.builder()
.setSubject(authentication.getUsername())
.claim("roles","user")
.setIssuedAt(new Date())
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512,jwtSecret)
.compact();
The above class generates a token and respond back to the user. My question is how I'm going to delete the token when a user issue a new token before the first token expire time; to revoke the first token when a user request a new token before the first is expired?
I don't think that's possible to do with JWT.
You could
Add the old one to some fast storage (like Redis or memcached)
Set some timeout on the value (a little big longer than the expire date of no longer wanted token)
Check if the token from request exists in your cache, if yes then reject it
basically, do the blacklisting
I'm not aware of any other solutions
If you use JWT, you can't revoque the token. Its validity is embedded.
When you want to revoke a token, don't use JWT. You must persist the token and check its validity at every request.
If you really want to use it, save it in db as if it's not independent and add a flag or a timestamp for validity.
Check JWT documentation : https://jwt.io/
Related
I am currently implementing Contact Application using Google Contact API in Java. I have completed steps of authorization and obtained an access token and a refresh token.
Now I have the CLIENT_ID , CLIENT_SECRET AND REFRESH_TOKEN with me . But the access token is getting expired within an hour.
Can someone tell how to automatically generate an access token using a refresh token in Java?
You can use Google OAuth2 client library for getting a new access token using a refresh token.
Here is my code for getting a new access token:
public TokenResponse refreshAccessToken(String refreshToken) throws IOException {
TokenResponse response = new GoogleRefreshTokenRequest(
new NetHttpTransport(),
new JacksonFactory(),
refreshToken,
"your clientId",
"your clientSecret")
.execute();
System.out.println("Access token: " + response.getAccessToken());
return response;
}
For more information read the official Google API guide:
OAuth 2.0 and the Google OAuth Client Library for Java
I have implemented this scenario in two ways. Not sure they are the best or not but works well for me.
In both cases you have to store the refresh token along with the email id of the user. Then you have to make a HTTP request in the below format.
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
client_id=**<your_client_id>**&
client_secret=**<your_client_secret>**&
refresh_token=**<refresh_token>**&
grant_type=refresh_token
It will return the access_token and expires_in
Source
Now the question is how and when to do the http request. So for that I have two ways.
1st one
Store the emailid,refresh token, access token and the current time+3600 seconds. In your database you can schedule to check the expire time in every 5 min and if current time of any user is going to reach(before 5 or 10 min) the expire time, get the refresh token and update the value for that particular user. And during api call just fetch the access token of the user.
2nd one
When user do login in your site, get the access token and current time+ 3600secs and store it in browser cookies. Now before doing any api call just check whether the current time(time when api call is done) is less than the expire time(stored in cookie). If its true then you can use the previous access token else get a new one and again update the cookie. Also you have to put another condition that if the cookie is not present at all then also you have to get new refresh token.
I am using jjwt to create token using the documentation on github https://github.com/jwtk/jjwt#specification-compliant
I understood that I have to create a refresh token store it on my database and use it to create an access token for the user. But I don't find a simple example to help me to understand how to code it. I am able to create a token following the github documentation but i don"t know how to create a refresh token and then an access token using my refresh one.
I am using java on android studio and as back up api using App Engine Java servlet module
even that it has been a long time since then:
You have 2 tokens: one that expires fast (token) and one that expires after a very LONG TIME (refresh token).
The reason for this is because refresh token is actually used very rarely and you don't send it over the network so often. if you send a token very often over the network you have to make it expire fast (it's up to you to decide how long a token lives 30 mins/1 hour/2 days).
When the JWT token where you store the data has expired you use the refresh token (from client side which should be stored securely) and get another token that you send very often over the network.
The flow should be like this:
login with credentials => get token (2hours expiry) and refresh token(30 years expiry);
client stores both tokens securely
token expired
using refresh token make a request and get another token that expires in 2 hours
refresh token expires after 30 years - logout the user
The refresh token is just used to not put the user insert credentials again
Well, it has been a long time, but I think neither of already posted answers actually addresses the original question. Let me handle it:
You should understand, that, technically speaking, your Refresh Token could be anything. Let me explain: you need Refresh Token just to later on reissue an Access and Refresh tokens pair. In most cases, you should store your Refresh Token in database (or in-memory Cache, like Redis). Technically you do not obligated to sign a Refresh Token, or encrypt it. Do the following:
Generate Access Token (and of course, it must be signed)
Generate Refresh Token the way you want. It can be almost the same JWT, but with far more extended TTL (Time to live). Store it in some data storage, again depends on your requirements
Once the Access Token get expired, the Client, to which you have issued tokens, come to you with the Refresh Token you have generated on the step 2. You will pull Refresh Token you have saved on the previous step, check for their equality. If everything is alright (Refresh Tokens matches) - repeat procedure from the first step. That is it.
Hope it helped
Creating a refresh token is just creating a "normal" token with new (refreshed) data (claims) in it.
It only makes sense if your claims that the server issues change over the time like e.g. the expiration time. Obviously only the token issuer (I assume the server in your case) can refresh the tokens and client needs to poll for them or the server needs to notify the client.
On the server just create the new token with a future expiry time filled in:
Calendar cal = Calendar.getInstance(); // creates calendar
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
cal.getTime();
String compactJws = Jwts.builder()
.setSubject("Joe")
.setExpiration(cal.getTime();) // set expiration to e.g. one hour in the future
.signWith(SignatureAlgorithm.HS512, key)
.compact();
Hint: you cannot invalidate JWT tokens apart from putting them on a central blacklist what kind of cannibalizes the concept of JWT.
I implemented JWT authentication for my Spring boot app. Overally, it works like this:
Client sends username, password to the login endpoint.
Server checks if the provided credentials are valid.
If no, it would return an error
If yes, it would return a token, that token actually includes
Client sends that token with every future request
The question is, how should we implement logout ?
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
class TokenAuthenticationService {
static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
static void addAuthentication(HttpServletResponse res, String username) {
String JWT = Jwts
.builder()
.setSubject(username)
.setExpiration(
new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
static Authentication getAuthentication(HttpServletRequest request, UserDetailsService customUserDetailsService) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
Claims claims = Jwts.parser().setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
String userName = claims.getSubject();
Date expirationTime = claims.getExpiration();
if (expirationTime.compareTo(new Date()) < 0) {
return null;
}
UserDetails user = customUserDetailsService.loadUserByUsername(userName);
return user != null ? new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(), user.getAuthorities()) : null;
}
return null;
}
}
addAuthentication is used by the JWTLoginFilter class to send the authentication code when logging in, 'getAuthenticationis used by theJWTAuthenticationFilter` that filter all requests to the end points.
What is the best practice here ?
I don't think there is a best practice here. I guess it depends on the application you're building and it's requirements.
The benefit of JWT is that they're stateless. You don't need to query the database to validate the token. This is good when you wish to reduce the load on your database but bad when you want to invalidate an existing non-expired token.
Possible solutions:
Store JWT in the database. You can check which tokens are valid and which ones are revoked but this defeats the purpose of using JWT at all in my opinion.
Delete token from the client. This would stop the client from being able to make authenticated requests but if the token is still valid and somebody else has access to it, the token could still be used. This leads me to my next point.
Short token lifetime. Let the tokens expire quickly. Depending on the application, it could be several minutes or half an hour. When the client deletes its token, there's a short window of time where it can still be used. Deleting the token from the client and having short token lifetimes would not require major modifications on the back-end. But short token lifetimes would mean that the user is constantly being logged out because the token has expired.
Rotate tokens. Maybe introduce a concept of refresh tokens. When the user logs in, provide them with a JWT and a refresh token. Store the refresh token in a database. For authenticated requests, the client can use the JWT but when the token expires (or is about to expire), let the client make a request with the refresh token in exchange for a new JWT. This way you would only have to hit the database when a user logs in or asks for a new JWT. When the user logs out, you would need to invalidate the stored refresh token. Otherwise somebody listening in on the connection could still get new JWTs even though the user had logged out.
Create a JWT blacklist. Depending on the expiration time, when the client deletes its token, it might still be valid for some time. If the token lifetime is short, it might not be an issue, but if you still wish that the token is invalidated immediately, you could create a token blacklist. When the back-end receives a logout request, take the JWT from the request and store it in an in-memory database. For each authenticated request you would need to check your in-memory database to see if the token has been invalidated. To keep the search space small, you could remove tokens from the blacklist which have already expired.
I don't know what's best practice, but in a system whose internals I have seen, there is a central authentication manager which knows all the currently valid authentication tokens, so logging out would simply consist of removing the token from the collection of valid tokens.
So, next time the authentication manager is asked whether the token is valid, it would respond with a "no".
1) Simply remove the token from the client
2) Create a token blacklist
3) Just keep token expiry times short and rotate them often
Please have a look at Invalidating JSON Web Tokens
Invalidating JSON Web Tokens
I have created a JWT token along with expiration time for authentication purpose.
Each time
when a url hits in the application i am checking for the token. I want to increase the JWT token expiration time. The following is how i done. but the token is expiring by taking the expiration time which is already set while creating the token.
//creating JWT token only once when user logged in
String jwtToken = new String(Jwts.builder().setSubject(user.getUserId())
.setExpiration(expTime).setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "secretkey").compact());
// checking the presence of token every time
Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(jwtToken).getBody();
claims.setExpiration(time); // trying to reset the expiration time
I don't know what's going wrong. Any help would be much appreciated.
I think the expiration time is part of the token itself and it's not possible to extend the expiration time of a token without a new one.
Please refer to JWT (JSON Web Token) automatic prolongation of expiration for more discussion about this.
You'll need to recreate the token. All the information in the token is signed, making the token unique depending on the values in the token. Changing the claim that you pull from the token doesn't do anything.
It seems expTime defined in the previous code lines.
ex:- You can change this value.
int expTime = 43200000 //after 12 hours(Should in ms)
I think the best practice is to set this in the property file as follows. Then you can change that time after building the project.
app.expTime=43200000
After that call this value from token provide file
#Value("${app.expTime}")
private int expTime;
We are using restFB 1.6.12. I am getting the facebook access token in two ways,
1. CLIENT_APP_ID = "XXXXXXXXXXXXXXXXXX";
CLIENT_SECRET = "XXXXXXXXXXXXXXXXXX";
REDIRECT_URL = "XXXXXXXXXXXXXXXXXX";
AUTH_CODE = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
SCOPE = "email,read_stream";
Redirect to facebook as the example. As a result I'll get an
authorization code
https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream
asking for an access_token using,
https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
this returns the access token like this,
access_token=CAAHWfjdHDKcBAIL0zHMeJKzJw8Ug7WrrrkNxpBnK7ubnFR1RGtIIZA7T3UPlhCSV0hPJXZAgTcKfBSfHZAyxsndc3RT72XMREjACxnGb0ZCGMZAUgDWH3FgOhnaoSBMgkaQBPDOCCEKcLnznMYSncWS7dVxl9IFrSzeFjF6LKOWB3NTynl5X1&expires=5125218
2. AccessToken accessToken = new
DefaultFacebookClient().obtainAppAccessToken(appid,appsecret);
String token=accessToken.getAccessToken();
It reurns the access token like this,
access_token=517312558337191|5oHY9T3cZICO_TCeK8OdXKg5Y08
If I use the first(1) one, it works fine for first access after then every access throws an error
Auth Token= {"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100}}
If I use the second(2) one, it works fine only for publicSearchMessages but when I access publicEvents or other searches it throws an error
com.restfb.exception.FacebookOAuthException: Received Facebook error response of type OAuthException: (#200) Must have a valid access_token to access this endpoint
at com.restfb.DefaultFacebookClient$DefaultGraphFacebookExceptionMapper.exceptionForTypeAndMessage(DefaultFacebookClient.java:766)
at com.restfb.DefaultFacebookClient.throwFacebookResponseStatusExceptionIfNecessary(DefaultFacebookClient.java:688)
at com.restfb.DefaultFacebookClient.makeRequestAndProcessResponse(DefaultFacebookClient.java:630)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:592)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:556)
at com.restfb.DefaultFacebookClient.fetchConnection(DefaultFacebookClient.java:219)
My question is, what is the difference between these two access token and how can I programmatically generate access code for first one to works publicSearchMessages, getPublicEvents and other searches?
Which one access token is used to works as expected?
Access_tokens allow users to interact with your apps in secure and social ways. While we are removing the use of the offline_access permission, through a migration setting in the App Dashboard, we are now allowing the option to use access_tokens with a long-lived expiration time that can be renewed each time the user revisits your app
When a user visits your site with an existing, valid, short-lived user access_token, you have the option to extend the expiration time of that access token.
extend the expiration time once per day, so even if a user revisits your site multiple times a day, the token will be extended the first time requested. You must make sure to call the new endpoint below before the short-lived access_token expires.
Using the new endpoint below, you will be able to extend the expiration time of an existing, non-expired, short-lived user access_token.
To get the long-lived user access_token simply pass your own client_id (your app_id), your app_secret, and the non-expired, short-lived access_token to the endpoint. You will be returned a new long-lived user access_token; this access_token will exist in addition to the short-lived access_token that was passed into the endpoint
In short Get a page access token – those don’t expire per default; and make sure to do so with a long-time user access token
You can access facebook doc here for more info
To get an extended Page Access Token, exchange the User Access Token for a long-lived one and then request the Page token. This "extended" token for Pages will actually not have any expiry time.
https://developers.facebook.com/docs/howtos/login/extending-tokens/#step1
resolve this by executing a curl request, and saving "Page access token" in your code manually