Is this use-case supported for Spring Security 5, or something else, where we don't have to reinvent the wheel? Thoughts on how to (re)implement this better?
Details are as follows. 3rd party vendor supplied endpoints. We pull info from upstream source then forward to the downstream vendor. Only 2 APIs are required:
Request Access Token
Save Info
Both are actually being called via a gateway. We've been given specifics:
(A)
The token request requires Basic Auth (standard header - usual base64 encoded). Gateway User and Gateway Password are provided.
Credentials for request token are provided to us:
Grant Type = password
Consumer Id
Consumer Secret
Account User
Account Password
It responds with an access token and few other details we don't really care about and of zero value to our use-case.
There is no expires_in info in the response. But I've tested it multiple times to know it does expire. Not sure how long right now, I could do more tests to determine that.
(B)
The save request requires a different custom header for the same Gateway User / Password, then a Bearer Authorization header in the call to the Save Info API.
Right now, all implementations for above are using RestTemplate. Working fine already. But a token is requested for each save which is costly. Before writing any caching, or some other logic to wait XY minutes before another token request is made, I would appreciate any other options which may already be possibly handled via Spring-specific libraries or further advise on how to handle this scenario.
Apologies if this is not the right place to ask this, or it has already been asked before. Been searching for a similar use-case but can't seem to find one.
Thanks.
Try any one of the option
You can use OAuth2ClientContext which stores your access token.
final OAuth2RestTemplate restTemplate=new OAuth2RestTemplate(resourceDetails, clientContext);
You can create session & store your token & user details inside it.
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(user, null,null);
SecurityContextHolder.getContext().setAuthentication(authToken);
from option 1 Or option 2 you can then fetch existing token for each request at your Filter e.g. PRE_AUTH_FILTER
Then check if token expired - if yes request new token Or call refresh token
Check Oauth2 expires_in in below :-
https://www.rfc-editor.org/rfc/rfc6749?
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 am writing a REST client in Java using the HttpCLient , the REST API that I access needs an auth token for every REST action. This token is valid for 24 hours.
The way I am handling this now is calling a "getAuth()" method everytime I need to make a REST call which seems like an overhead on the auth server.
How can I conveniently store this auth token and manage its life cycle?
Are there any documented best practices?
I thought of the following solution
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
and then pass the sessions object to any class that nees the token. If the token is expired, just call this method again
For brevity I'll assuming you're calling an endpoint that you can't change. How you should implement will heavily depend on whether the token is app or user based (one token for all users on a shared app instance or one token per user).
If it's one auth token for the entire app:
Store it in memory along with a time-to-live timestamp (or alternatively catch the token expired error, request a new token and retry the original request), refresh it if it doesn't exist/is expired
If you're concerned about re-requesting API tokens after an application restart also store it in the database and load it at startup if it exists
If it's one token per user:
Store it in your user session, it's exactly what sessions are used for, if you're authing users then they'll have a session and the overhead is already there
If you don't want to re-request a token everytime they login store their current token in the DB and and load it into their session when they login
I'm assuming you are using OAuth for authorization. Whether you are using JWT or other tokens is irrelevant to this situation.
When performing authorization you will be issued an access_token with an expiration and, depending on the grant type you are requesting (Client credentials, Authorization code, Implicit, Resource owner), a refresh_token.
The client should keep the access_token and the expiration. The refresh_token, if issued, must be kept secret (beware of using the correct grant for your use case).
In subsequent calls, your client should not request new tokens on each call, it should use the stored access_token.
Once the API starts returning 401 Unauthorized, the access_token has probably expired. Your client should try to refresh the access_token using the refresh_token if you got one.
If you have no refresh_token or the refresh request also failed, because the refresh_token is no longer valid, you can perform a new authorization flow.
You can use the expiration time as a clue to know when to get a new access_token either through refresh or through a new full authorization flow. This will avoid the 401 Unauthorized. In any case, your client should have a fall back policy when this response is received after having used a valid access_token for some calls.
You can create a manager and store the auth-cookie during login in thread local like the code below. You can get the cookie from getAuth() as long as the thread lives.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
I suggest you to use the following scenario:
1) First, call auth(username, password) rest api to get the auth token.
If the given credentials are okay then just send back the auth cookie to the client with HTTP 200 response code.
2) Then, you can call protected rest apis. You need to send auth cookie with your request each time.
3) Servlet filter (or something similar) checks each incoming request and validates the token. If the token is valid then the request goes forward to the rest method, if not you need to generate an http 401/403 response.
I suggest you not to write your own authentication layer. Instead of install and use an existing one. I suggest you OpenAM. It is a superb open source access management system.
I also suggest you not to open session on the server side for authentication purpose. If you have 10 clients then 10 sessions needs to be managed by server. It is not a big issue. But if you have 100 or 1000 or millions different clients than you need more memory to store sessions on the server.
If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.
I would not recommend using Session in your case, but rather store the token in a cookie on the client.
In a high traffic environment(which i'm assuming yours is), the use of Session can consume a lot of server memory, and scalability can be a concern as well, having to keep sessions in sync within a cluster.
As #Cássio Mazzochi Molin also mentioned, you can use an in-memory cache to store any user specific data and tokens. This will reduce the hits to the database, and also allow you to scale the application easier, when the need arises.
The de-facto standard is not implementing your own solution (basic rule in security: don't implement your own stuff!), but use the de-facto standard solution, namely JSON Web Tokens.
Documentation on the site, but the basic idea is, that you only need to store one value (the server's private key), and then you can verify every claim, issued originally by the server (which will in your case contain an expiry time).
You should use JsonWebToken (JWT in short) for this kind of stuff. JWT has build in support to set the expiration date. There are plenty of libraries to use this method and you can read more here
There are currenlty 4 java implementations and all of them can check if the token is still valid (exp check)
So if I'm understanding correctly you are using the same token for all of your requests (which means as long as your app is up and running and you refreshing the tokens, you should be ok. I literally had the same problem and this is how I've resolved it. I have a singleton class, which is initialized at the app start for once and refreshes the token when its invalidated. I'm using C#, Asp.NET MVC5 and AutoFac for DI, but I'm sure you can do the same with Java and Spring.
Updating property of a singleton with Thread Safety
Use json web tokens , to exchange information between two clients. The token will only alive for the 24 hours period, after that time all consequent calls in the header will be rejected.
Auth Token for each request is correct approach, Consider auth server scaling for performance issue.
On first successful authentication (username and password), generate private public keypair. Store private key as Session Security Token (SST) and send public key as Public Security Client Key (PSCK) to client
In all request other than login (or authentication) client will send PSCK to protect theft of username and password and server can verify PSCK for expiry internally at regular intervals saving processing time.
If system is having performance issue on authentication side, setup seperate auth server with scalability.
No token or password to be cached, exchanged unencrypted and send outside security zone. Do not post using URL parameters.
I am integrating google calendar api, I have a url that is the redirect url after the application access is authenticated, the url returns a parameter code like
redirectUrl/code?='somecode'
i want to know the time expiry for the parameter code
The default is 3600 seconds, or an hour. But if you make requests after that, the previous code will be invalid, but I'm sure you know that.
https://developers.google.com/accounts/docs/OAuth2UserAgent#handlingtheresponse
The expiry of the access token is 3600 seconds only.
it could be revoked using refresh token or the access token it self, you may use the refresh token if the approval prompt for the google approval is kept "auto", but in the case you would get refresh token only once, using refresh token the response does not returns refresh token in this case but if you will use access token refresh token shall be generated with it, but if you use approval prompt of "force" type then you shall get the approval window every time.