I would like to know what's the best and secured way to send the JWT generated in my spring boot app to my Flutter mobile app. I can send it in the response body which I know that's not a good practice in web but is it a problem when it comes to mobile?
This is how I return the JWT:
public ResponseEntity<?> signin(String username, String password) {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
String token= jwtTokenProvider.createToken(username, userRepository.findByUsername(username).getRoles());
//return new JwtResponse(token,username,userRepository.findByUsername(username).getRoles());
return ResponseEntity.ok(new AuthToken(token));
} catch (AuthenticationException e) {
throw new CustomException("Invalid username/password supplied", HttpStatus.UNPROCESSABLE_ENTITY);
}
}
IT doesn't matter how you send your JWT token, in the Header or in the body portion. it can easily be seen and copied by others through some app on the client-side.
The steps you can take to secure your data is
firstly You need to check if the Token is tampered with by the client, every time you receive a JWT token from the client
Secondly, you should add a created-at field where you send a timestamp of when the Token was created. This will prevent someone to pose as the owner of the token forever after this is stolen, as this Token will be invalid after some time.
and you can send your token simply in the body part of the response after taking those security measures. Of course, there are many more best practices to follow but these are a good starting point.
Related
I am new to Okta so apologies if my questions are not clear.
So what I want to do is basically parse the JWT token generated by
okta and extract the group information of the logged in user
associated with it.
I am under the impression that this information should be there in the
OidcUser object. I do see user name/email id / token validity etc
information inside this object. Unfortunately I can't see group id
which I need for further processing.
#RequestMapping("/")
public String hello(#AuthenticationPrincipal OidcUser user){
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : user.getClaims().entrySet()) {
sb.append(entry.getKey() + ":" + entry.getValue().toString());
sb.append("\n");
}
sb.append("|");
sb.append(user.getClaims());
return sb.toString();
}
Here is my okta plugin inside spring boot
okta.oauth2.issuer=https://dev-XXXXXXXX.okta.com/oauth2/default
okta.oauth2.client-id=XXXXXXXXXX
okta.oauth2.client-secret=XXXXXXXXXXXX
I am wondering if my approach is proper and what more I need to do to extract User group from Okta JWT token.
To get user groups you need to make an additional request to /userinfo endpoint, assuming you requested groups scope during /authorize call.
Please see a guide here
Not exactly spring-boot response, but it's always beneficial to know how things work under-the-hood
I'm sending the request with jwt token in Authorization. I need to fetch it somehow and I tried by this way:
#GetMapping
fun getUser(#AuthenticationPrincipal jwt: Jwt<*, *>): ResponseEntity<UserDto?> {
val allClaimsFromToken: Claims? = getAllClaimsFromToken(jwt.toString());
val userNameFromJwtToken: Any? = allClaimsFromToken?.get("sub");
....
}
Unfortunately I get all the time null as jwt variable. Could you tell me what am I doing wrong?
Probably the most straight forward way of doing this would be to get the raw header value and then parse it with JJWT.
#GetMapping
fun getUser(#RequestHeader (name="Authorization") tokenEncoded: String): ResponseEntity<UserDto?> {
Jwt myToken = Jwts.parserBuilder()
.setSigningKey(yourKeyHere)
.build()
.parseClaimsJws(tokenEncoded.removePrefix("Bearer").trim());
// do something
}
You could also look into using the Spring library for OAuth2 it automates a bit more. Or you can create a filter that does the parsing so you don't have to repeat this on every web call.
Also see this post for further ideas Accessing JWT Token from a Spring Boot Rest Controller . It's Java, but basically the same applies.
I'm working on this Spring Security implementation with OAuth2 and JWT:
According to the author I can access resources using token this way:
To access a resource use (you'll need a different application which has configured ResourceServer):
http localhost:8080/users 'Authorization: Bearer '$ACCESS_TOKEN
About this step:
To use the refresh token functionality:
http --form POST adminapp:password#localhost:9999/oauth/token grant_type=refresh_token refresh_token=$REFRESH_TOKEN
It's not clear for me when I need to refresh the token and how to handle this part into Angular.
When the Token expires do I need to first send request to the endpoint for refreshing the token and then to the login page?
How this case should be implemented?
At the time of authentication, two JWTs will be created - access token and refresh token. Refresh token will have longer validity. Both the tokens will be written in cookies so that they are sent in every subsequent request.
On every REST API call, the tokens will be retrieved from the HTTP header. If the access token is not expired, check the privileges of the user and allow access accordingly. If the access token is expired but the refresh token is valid, recreate new access token and refresh token with new expiry dates and sent back through Cookies
Access tokens carry the necessary information to access a resource directly. In other words, when a client passes an access token to a server managing a resource, that server can use the information contained in the token to decide whether the client is authorized or not. Access tokens usually have an expiration date and are short-lived.
Refresh tokens carry the information necessary to get a new access token. In other words, whenever an access token is required to access a specific resource, a client may use a refresh token to get a new access token issued by the authentication server. Common use cases include getting new access tokens after old ones have expired, or getting access to a new resource for the first time. Refresh tokens can also expire but are rather long-lived.
High level code
authenticate()
public ResponseEntity<OAuth2AccessToken> authenticate(HttpServletRequest request, HttpServletResponse response, Map<String, String> params) {
try {
String username = params.get("username");
String password = params.get("password");
boolean rememberMe = Boolean.valueOf(params.get("rememberMe"));
OAuth2AccessToken accessToken = authorizationClient.sendPasswordGrant(username, password);
OAuth2Cookies cookies = new OAuth2Cookies();
cookieHelper.createCookies(request, accessToken, rememberMe, cookies);
cookies.addCookiesTo(response);
if (log.isDebugEnabled()) {
log.debug("successfully authenticated user {}", params.get("username"));
}
return ResponseEntity.ok(accessToken);
} catch (HttpClientErrorException ex) {
log.error("failed to get OAuth2 tokens from UAA", ex);
throw new BadCredentialsException("Invalid credentials");
}
}
refreshToken()
Try to refresh the access token using the refresh token provided as a cookie. Note that browsers typically send multiple requests in parallel which means the access token will be expired on multiple threads. We don't want to send multiple requests to UAA though, so we need to cache results for a certain duration and synchronize threads to avoid sending multiple requests in parallel.
public HttpServletRequest refreshToken(HttpServletRequest request, HttpServletResponse response, Cookie refreshCookie) {
//check if non-remember-me session has expired
if (cookieHelper.isSessionExpired(refreshCookie)) {
log.info("session has expired due to inactivity");
logout(request, response); //logout to clear cookies in browser
return stripTokens(request); //don't include cookies downstream
}
OAuth2Cookies cookies = getCachedCookies(refreshCookie.getValue());
synchronized (cookies) {
//check if we have a result from another thread already
if (cookies.getAccessTokenCookie() == null) { //no, we are first!
//send a refresh_token grant to UAA, getting new tokens
String refreshCookieValue = OAuth2CookieHelper.getRefreshTokenValue(refreshCookie);
OAuth2AccessToken accessToken = authorizationClient.sendRefreshGrant(refreshCookieValue);
boolean rememberMe = OAuth2CookieHelper.isRememberMe(refreshCookie);
cookieHelper.createCookies(request, accessToken, rememberMe, cookies);
//add cookies to response to update browser
cookies.addCookiesTo(response);
} else {
log.debug("reusing cached refresh_token grant");
}
//replace cookies in original request with new ones
CookieCollection requestCookies = new CookieCollection(request.getCookies());
requestCookies.add(cookies.getAccessTokenCookie());
requestCookies.add(cookies.getRefreshTokenCookie());
return new CookiesHttpServletRequestWrapper(request, requestCookies.toArray());
}
}
I am using Owin middleware to implement token-based security for my application. When issuing the access token to the client I would also like to pass User Id along with the token, so that, the client application will know the User Id and will be able to call GetUserById (one of the methods inside UserController) in order to show the user his starting page. The best solution I could come up with so far is just adding User Id to the response header. Take a look at my OAuthAuthorizationServerProvider class, in GrantResourceOwnerCredentialsmethod I am adding User Id to the header, using context.Response.Headers.Add("User-Id", new string[] { "1" })
Here is the implementation of my OAuthAuthorizationServerProviderclass
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
//The actual credential check will be added later
if (context.UserName=="user" && context.Password=="user")
{
identity.AddClaim(new Claim("Id", "1"));
context.Validated(identity);
//Here I am adding User Id to the response header
context.Response.Headers.Add("User-Id", new string[] { "1" });
}
else
{
context.SetError("invalid_grant","The credentials provided are not valid");
return;
}
}
}
Basically the client then will have to read User-Id from the header. Is this a good solution I came up with or there is a better one? Also what if I want to pass the whole User object with all its properties to the response is it possible and how to do this?
Since you store the ID already in the claims, why don't you just decode your token on the client and read out the user id like that? Passing it through the headers could allow tampering with it (security).
Have a look on how you could achieve to decode your token and read the claims. This is a c# example https://contos.io/peeking-inside-your-jwt-tokens-using-c-bf6a729d06c8 but this could also be done even through javascript.
This, assuming you use the JWT-format as token (was not specified in your initial question).
Bad way to store UserID as a response header back to client side. This is a huge security concern.
The best way would be to store it as a Claims.
It is very easy to achieve this and get back the claims in the client side.
In your controller, call this and remember to reference
using Microsoft.AspNet.Identity;
var userId = User.Identity.GetUserId();
I am building an ASP.NET Web API. I am using YouTube API to upload videos on YouTube. I have managed to implement the OAuth with refresh token flow. After generating a refresh token I am using the following code for all the subsequent calls to YouTube API.
var token = new TokenResponse { RefreshToken = REFRESH_TOKEN };
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets { ClientId = CLIENT_ID, ClientSecret = CLIENT_SECRET }
}), "user", token);
YouTubeService service = new YouTubeService((new BaseClientService.Initializer()
{
HttpClientInitializer = credentials
}));
I want to know when this refresh token will expire and how I would regenerate this refresh token without any user input/interaction so that end user does not see a Google account selection screen (in my case I see two accounts, a gmail one and a YouTube channel's one).
Also, if I have one refresh token generated, then I do not get a refresh token in response if I try to initiate the OAuth process again by using https://accounts.google.com/o/oauth2/auth again. Can I only have one refresh token at a time?
There are examples, also in the documentation and other similar questions here. However, maybe not in your programming language.
The refreshToken should be saved by you and reused. It is valid until it gets revoked by the user himself. Getting a refreshToken requiers user interaction.
Once you have obtained the refreshToken use it in another request to obtain an accessToken. The accessToken is needed in YouTube API requests for some data access. An accesToken expires after 1 hour (3600 seconds), although this period could be changed in the future.