I have been given a spring boot web api project. There is a flutter application that will send a jwt token as a request and the api has to get the "ticket" value out of the payload and then check the database and send the required data. I am totally a newbie in this field but I have no choice rather than complete it.
I wanted to make the matter easy by just accepting the token and try to decode that and get the "ticket" value out. But I was unable to do so as I am unable to get the token in the very first place.
The authentication is being done by some other api and that is providing the jwt token to the flutter application. Then the flutter application will send that token in any request to my api. I have a sample database with the data required and will have to resolve the request using "ticket" (which is acting as a username) from the database and will provide the data. I don't have to perform any authentication part - I just have to extract the token from the request - decode that and get the "ticket" value and have to search the database and provide the data.
token : eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
reuest : localhost:8080/persons?access_token=eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
The code is not necessary I just want to learn how it works. There are many videos in YouTube but they all are concentrated on the authentication which I don't have to perform and none is showing how the request from the application is to be handled. Any resources will also be a great help. Thank You.
reuest : localhost:8080/persons?access_token=eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
From the above request, you can design the controller like as follows :
#GetMapping("/persons")
public ResponseEntity loadPersons(#RequestParam("access_token") String access_token,HttpServletRequest request){
//Here you can play with the token now
//you can also get the token if it is coming with request header as follows :
String token =request.getHeader("access_token");//replace with the specific key
}
e.g.
public boolean isValidJWTToken(String jwtToken){
boolean isValid = true;
try {
Jwts.parser().setSigningKey(generateKey()).parseClaimsJws(jwtToken);
} catch (Exception e) {
isValid = false;
}
return isValid;
}
private Key generateKey() {
byte[] keyBytes=environment.getProperty("auth.jwt.secret.key").getBytes();
return new SecretKeySpec(keyBytes, 0,keyBytes.length,environment.getProperty("auth.jwt.secret.algo"));
}
TheJWT Token has 3 parts .
1. HEADER:ALGORITHM & TOKEN TYPE
2. PAYLOAD:DATA
3. SIGNATURE
All the above 3 parts are your business driven. So you can better know which is the algo used for encode . Accordingly, you can do decode.
Related
Trying to read data of specific envelopes from DocuSign using completely backend java process ... and after some trial and error I've obtained AccessToken with JWT grant but still getting authorization error when asking for actual data :(
Defined new integration key 9xxx7e
User Application: Authorization Code Grant
No secrets added
Service Integration - uploaded public RSA key
Added one Redirect URI (regardless I don't need any)
Manual confirmation of corresponding link : https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=9xxx7e&state=123&redirect_uri=https://my.redirect.net/DocuSign ... assuming it is just one-time action
Successfully requested Access Token using java code (using com.docusign:docusign-esign-java:3.10.1)
ApiClient = new ApiClient(ApiClient.DEMO_REST_BASEPATH);
OAuthToken token = apiClient.requestJWTApplicationToken(integrationKeyJwt, scopes, privateKeyFileContent, 3600);
Trying to get envelope data using simple HttpGet
HttpGet request = new HttpGet("https://demo.docusign.net/restapi/v2.1/accounts/6xxx1e/envelopes");
request.addHeader("Content-Type", "application/json");
request.addHeader("Authorization", "Bearer " + token.getAccessToken());
but still got 401 response with content:
{"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"The access token provided is expired, revoked or malformed. Authentication for System Application failed."}
Please any idea what is wrong? How to obtain correct Access Token?
P.S.: I also tried to get Authorization Code Grant without JWT or implicit grant but no luck without browser tough :(
I would recommend that you print the accessToken you're creating in a file and use in Postman. This will at least help you narrow it down to either the Token generation step or sending the request portion.
Let us know what you find.
Problem was/is with use of apiClient.requestJWTApplicationToken but apiClient.requestJWTUserToken is the way to go
I tried to get graph api token from postman UI and was able to get planner data.
How to achieve same in java spring
I am not able to get access token for Microsoft graph api using java spring. I am able to get access token using postman.
I need to access planner API from one of the web application. As per Microsoft documentation I configured a app in azure active directory and got client key, secret key etc.
I also configured required permission to get groups and users.
Very first time I used below from POSTMAN
https://login.microsoftonline.com//oauth2/token with below data
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
grant_type : client_credentials
resource : https://graph.microsoft.com
I got token, and I was able to get groups from https://graph.microsoft.com/v1.0/groups/
But same token was not valid for getting plans of group.
With lot of digging, I came to know that token accessed with client_credentials is not applicable to get data from planner API. So, next I used below details to get access token from UI of postman.
Grant Type : authorization_code
Callback URL : https://www.getpostman.com/oauth2/callback
Auth URL : https://login.microsoftonline.com/<tenant_id>/oauth2/authorize?resource=https://graph.microsoft.com
Access Token URL : https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
I got the Microsoft login screen, and after successful login, I got token.
I could call planner API using this access token.
Now my question is how can I get this same token using java spring.
Also, my web app will be having background service running in scheduler calling graph API daily.
I do not want manual intervention here, but as told earlier, graph API will ask to login.
How to achieve above requirement.
private String getAuth() {
ConfidentialClientApplication app = null;
IClientCredential credential = ClientCredentialFactory.create(Appsecret);
try {
app = ConfidentialClientApplication.builder(MicrsoftAppId, credential).authority("https://login.microsoftonline.com/"+tenantId+"/").build();
}catch(MalformedURLException e) {
System.out.println(e.getMessage());
}
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton("https://graph.microsoft.com/.default")).build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(parameters);
try {
IAuthenticationResult result = future.get();
return result.accessToken();
}catch(ExecutionException e){
System.out.println(e.getMessage());
}catch(InterruptedException e) {
System.out.println(e.getMessage());
}
return null;
}
Here you go! This code is made for application permission (so not delegated). It only requires your client Id and secret to operate. You will need the microsoft graph jar for it to work (and the many jars supporting it).
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 get a valid code on the client side login of my application using angularJS Oauth Module GAuth.checkAuth(). and then GAuth.getToken().
The code is valid only for 1 hour and any API like GoogleDocs,Gmail accessed after 1 hour fails and needs relogin.
To overcome this I am trying to send the code to the server for getting AccessCode at Server so that I can send same with requests to GoogleDocs, Gmail etc
GoogleAuthorizationCodeTokenRequest req =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
// "https://accounts.google.com/o/oauth2/token",
"901142925530-21ia7dqnsdsdsndnsnnnfdc9cm2u07.apps.googleusercontent.com",
"6NSvw0efghyuuG8YGOBWPln79n",
authCode,
"http://localhost:8080");
req.setGrantType("authorization_code");
//req.put("refresh_token", authCode);
//req.put("access_type", "offline");
GoogleTokenResponse tokenResponse =
req.execute();
tokenResponse.getAccessToken()
Where authCode is the code I received in GAuth Token
But the call is failing and in response I get
400 Bad Request
{
"error" : "invalid_grant",
"error_description" : "Incorrect token type."
}
Any help is highly appreciated!
When the user first authenticates your application you are given an authorization code. You then need to take this authorization code and exchange it for an access token and a refresh token. Once the authorization code has been used it can not be used again.
grant_type=authorization_code
Denotes that you are asking Google to verifiy that your authorization code and give you a new access token and refresh token.
It sound to me like you are taking either the access token returned from that request and sending it to grant_type=authorization_code end point which is not going to work its the wrong type of code. hens the error you are getting of
400 Bad Request { "error" : "invalid_grant", "error_description" : "Incorrect token type." }
You will need to take the refresh token you are given. If there is one I am not sure that you can even get a refresh token from AngularJs. You can get one using java though.
A refresh of an access token in pure rest will look like this
https://accounts.google.com/o/oauth2/token
client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
Note the &grant_type=refresh_token. If you are using the Google api java client library it should handle all of that for you. However your tagging is a little confusing its unclear if you are trying to do this in java or angularjs which I do not believe will allow you to use refresh tokens. Again I am not an angular dev I could be wrong on that point.
Anwser:
You the code you are sending is not an authorization code. Only an authorization code can be sent to grant_type=authorization_code. Solution: Send an authorization_code
Types of Google codes and tokens:
There are three types of codes or tokens you should be aware of with Oauth2.
Authorization code.
Refresh token
Access token
When you request access of a user and they grant your application access you are given an Authorization code. The Authorization code is short lived it probably less then 10 minutes and it can only be used once.
The Authorization code is used to get the initial access token and the refresh token from googles authentication server. by using the grant_type=authorization_code
Access token are good for about an hour. They are used to make calls to google APIs
https://www.googleapis.com/plus/v1/people/me?access_token={your access token}
You can use the access token as often as you want during that hour assuming you don't blow out some quota.
Refresh tokens are used to request a new access token from the Google authentication server when the access token you have current has expired or you just want a new one. here the grant_type=refresh_token is used to request a new access token you are essentially telling google I am sending you a refresh token you know what to do.
additional reading
I have a coupe of tutorials that might help you out Google 3 Legged OAuth2 Flow and Google Developer Console Oauth2 credentials
Also helpful when learning Oauth: The OAuth 2.0 Authorization Framework
In general what is the best way to authenticate the access token in interceptors, If the access token information is stored in HashMap for each and every user, the hashmap grows as the number of users increases.
If we query database for every api request, it increases load on database.
Please mention if there are any other techniques you know.
And also what other things I need to consider while authenticating the access token for every request. What are the pre-processing and post-processing steps while authenticating access token.
Thanks in Advance.
Check out Json Web tokens. Using them allows your server to become stateless (not saving any sessions on memory).
Its concept is to pass a digital signed token, for every request, and checking that the signature is correct for integrity.
Json Web Encryption also can encrypt sensitive data along the token (such as user id).
This makes it very easy to work on a distributed environment
Check out this website: https://jwt.io/. There are some implementations in java and plenty of code examples to start with.
Some words about authentication with tokens
Once you are using JAX-RS, have a look at this answer that I wrote a while ago.
Your tokens can be any randon string persisted to some storage. On the other hand, JWT tokens allow you to have stateless authentication (no persistence). If you need to track the JWT tokens (to revoke them, for example), you must persist at least their identifier (the jti claim). A HashMap shouldn't be used to "persist" tokens (that's not a real persistence and it won't scale). Instead, consider a database like Redis.
To generate and parse JWT tokens, have a look this library created by Stormpath and maintained by a community of contributors. I currently use it in some applications and I can say with confidence that it works just fine and it's easy to use.
Keep reading for more details about the authentication process.
Authentication with tokens at a glance
In a few words, a token-based authentication follow these steps:
The client sends their credentials (username and password) to the server.
The server authenticates the credentials and generates a token.
The server stores the previously generated token in some storage along with the user identifier and an expiration date.
The server sends the generated token to the client.
In every request, the client sends the token to the server.
The server, in each request, extracts the token from the incoming request. With the token, the server looks up the user details to perform authentication and authorization.
If the token is valid, the server accepts the request.
If the token is invalid, the server refuses the request.
The server can provide an endpoint to refresh tokens.
Using JAX-RS to implement authentication based on tokens
The authentication starts when the server receives the hard credentials (username and password) of a user and exchanges them with a token that the client must send in each request:
#Path("/authentication")
public class AuthenticationResource {
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response authenticateUser(Credentials credentials) {
try {
// Authenticate the user using the credentials provided
String username = credentials.getUsername();
String password = credentials.getPassword();
authenticate(username, password);
// Issue a token for the user
String token = issueToken(username);
// Return the token on the response
return Response.ok(token).build();
} catch (Exception e) {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
private void authenticate(String username, String password) throws Exception {
// Authenticate against a database, LDAP, file or whatever
// Throw an Exception if the credentials are invalid
}
private String issueToken(String username) {
// Issue a token (can be a random String persisted to a database or a JWT token)
// The issued token must be associated to a user
// Return the issued token
}
}
A filter will be used to extract the token from the HTTP request and validate it:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader =
requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Check if the HTTP Authorization header is present and formatted correctly
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
throw new NotAuthorizedException("Authorization header must be provided");
}
// Extract the token from the HTTP Authorization header
String token = authorizationHeader.substring("Bearer".length()).trim();
try {
// Validate the token
validateToken(token);
} catch (Exception e) {
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED).build());
}
}
private void validateToken(String token) throws Exception {
// Check if it was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
}
}
For further details, have a look at this answer.
JSON Web Token
JSON Web Token (JWT) is defined by the RFC 7519 and I think it fits really well for your needs.
It's a standard method for representing claims securely between two parties (in this situation, client and server). JWT is a self-contained token and enables you to store a user identifier, an expiration date and whatever you want (but don't store passwords) in a payload, which is a JSON encoded as Base64.
The payload can be read by the client and the integrity of the token can be easily checked by verifying its signature on the server.
To find some great resources to work with JWT, have a look at http://jwt.io.
And remember: when sending sensitive data over the wire, your best friend is HTTPS. It protects your application against the man-in-the-middle attack.
Tracking the tokens
You won't need to persist JWT tokens if you don't need to track them.
Althought, by persisting the tokens, you will have the possibility of invalidating and revoking the access of them. To keep the track of JWT tokens, instead of persisting the whole token, you could persist the token identifier (the jti claim) and some metadata (the user you issued the token for, the expiration date, etc) if you need.
There are many databases where you can persist your tokens. Depending on your requirements, you can explore different solutions such as relational databases, key-value stores or document stores.
Your application can provide some functionality to revoke the tokens, but always consider revoking the tokens when the users change their password. When persisting tokens, always consider removing the old ones in order to prevent your database from growing indefinitely.
You can combine both HashMap and database. In your case, HashMap can be used as a cache. The first time user was authenticated, access token information of this user should store to HashMap. The next APIs, we will check if the access token is exist in HashMap. If it exists, we use it to authenticate, if not we will query from database and store it to HashMap.
You need to expire access tokens in HashMap that was not used for a duration.