Working on an Azure AD-based authentication using OAuth2 and its On-Behalf-Of authentication flow.
I am wondering how to actually check the token comparison between the initial token provided by the user and the final token being provided by the middle service principal to the third or other service principal.
My current approach is creating another endpoint inside my application #GetMapping("/otherSP") and then call it within my application(internal API call) like:
String token = webclient.get()
.uri(newServicePrincipalUri)
.attributes(clientRegistrationId("currentServicePrincipalId"))
.retrieve()
.bodyToMono(String.class)
.block();
The endpoint within is like:
#GetMapping("/otherSP")
public String getExchangeToken(#RegisteredOAuth2AuthorizedClient("otherSP-id")OAuth2AuthorizedClient oAuth2AuthorizedClient){
return oAuth2AuthorizedClient.getAccessToken().getTokenValue();
}
For the purpose of acquiring the JWT, this approach seems barbaric. Is there any better approach or proper approach on how to actually check it or obtain the exchanged token?
Related
I have a CustomAuthenticationProvider that does a POST request to an API with username and password for authentication and the API returns an access token with expiry time.
Where do I set this token, so I can use the same token to make further calls to the API as long as the user is logged in. I also wanted to validate the token for expiry time before making another request.
Is it right approach to add the token to a customAuthenticationToken that extends UsernamePasswordAuthenticationToken and set it in the SecurityContext.
Please let me know your suggestions.
The token needs to be in the 'authorization' header for all calls. The value should be 'Bearer ' + token. If you are using a browser it gets a bit messy - let me know.
To add the authorization bearer header to all calls from Spring Boot depends on the sort of client, eg
HttpClient httpClient= new HttpClient()
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
Where the token is stored as a, probably static, variable somewhere.
In the server side you need a Filter that validates the token and marks the request as authorised - quite a bit of work - look here
Well, if you need to call another REST API, then you need to set up an http client. Since you use Spring Boot 3, WebClient is a default option, but the flow is the same for any client.
You basically store your token anywhere in memory, implement isExpired check and refresh logic.
class TokenStorage {
private String token;
void refreshToken() {
var newToken = ...;
this.token = newToken;
}
boolean isExpired() { ... }
String getToken() {
return token;
}
}
And then setup your client with custom filter so that everytime you call API, it checks whether token is expired and refreshes it if so.
I have a controller method that has an argument OAuth2AuthorizedClient with annotation #RegisteredOAuth2AuthorizedClient.
ResponseEntity<String> getFoo(
#RegisteredOAuth2AuthorizedClient("custom") OAuth2AuthorizedClient client) {
OAuth2AccessToken token = client.getAccessToken();
....
}
In order to resolve this, spring look for OAuth token on OAuth2AuthorizedClientService which actually stores the previously authenticated tokens in memory.
Now, I have a scenario where I obtain JWT token from OAuth server outside of this spring resource server, and trying to authenticate this server by passing token using Authorization header.
But when spring trying to resolve OAuth2AuthorizedClient it is looking for token in-memory with the principle of JWT (which will obviously not found since token is not obtained on this server). Hence send new login redirection for new token.
Overall question would be, is it possible to resolve OAuth2AuthorizedClient with the JWT token (obtained ourside of the server) passed in Authorization header?
I am consuming a secured Restful Service that grants access through Basic Auth (Username and Password). I have successfully accessed the API service and consumed its API; however, I am still confused as to what is the right way to implement HTTP headers with Basic Auth. I would assume I should authenticate only once, but the way I have constructed my code, it looks like I need to authenticate API with each service method I create.
Should I create a helper method with the authentication and call it on each service?
If you are using Basic Auth you need to always include credentials with your request. In case of OAuth, tokens have expiry. In this case, a token caching mechanism for the duration of a little bit less than the expiration duration would do the trick.
The Basic Auth is a kind of no status authentication. That means the server wouldn't record. Every time you need to provide username and password with your request. Each request is equal to the Server.
For another authentication called OAuth, the first time you request with username and password, the server will return a token to the frontend, which has an expiration period. So, you request every time with the token through the filter, where checks the expiry of the token. If it's not expired, using the same token for requests, otherwise, making a request to get another token.
In lots of descriptions the first step is that user tries to acces a resource on server something like
https://fhirblog.files.wordpress.com/2014/06/oauth2sequencediagram.png
Now i got a Rest API with severel endpoints:
GET /server/resource1
DELETE /server/resource1/{uuid}
GET /server/resource2
...
implementation looks something like this:
#DELETE
public Response deleteResource(
#ApiParam(value = "The id", required=true)
#PathParam("uuid") String uuid,
#Context SecurityContext securityContext)
throws NotFoundException {
Until now i have implemented an apikey which is passed by header into the api and a filter that verifies teh apikey.
Now i want to implement a full (three/two legged) oauth 2.0 flow. But i am now wondering about the first step.
So Question is:
Do i have to add a mechanism on each endpoint that verifies if the request has a token? and if not redirect the request to an auth endpoint?
(Also
Can i send the Tokens in the HttpHeader or do the Tokens have to be in the Body of the Request?)
Or:
Do i have to create just one endpoint that does the token stuff and in my other resource endpoints i only verify if the token is valid?
Okay here are the explanations,
Do i have to add a mechanism on each endpoint that verifies if the request has a token? and if not redirect the request to an auth endpoint?
This question has two parts, so i will explain it separately for better understanding,
Do i have to add a mechanism on each endpoint that verifies if the request has a token?
Yes, in general the endpoints would be an APIs, so you need to setup middleware or interceptor or filters, to check to see does this endpoint need authorization if so check access token, if valid then proceed with request, if not return 401 Unauthorized as Http response, for example:
All request to /server/* must be accessed with access token, then you need to setup filter for those paths and check the access token,
if not redirect the request to an auth endpoint?
No, if access token is not provided or invalid or expired any case, you need to return Unauthorized http response like below,
Status Code:401
{"ok":false,"errors":[{"code":"unauthorized_request","message":"unauthroized request, access token either invalid / expired"}]}
here its json response, but any format works
So while the client make http request to access the endpoint, they need to pass the access token in HTTP Header like below,
Authorization: Bearer {access_token}
Do i have to create just one endpoint that does the token stuff and in my other resource endpoints i only verify if the token is valid?
Yes, you need to create an endpoint like /auth (typically called Auth Endpoints) to handle the authentication process, code exchange, refresh, revocation etc.
Then all other resource endpoints should just check token and process the request, and these endpoints wont take part in token management process
I am playing with the Spring Cloud OAuth2 implementation using the following examples:
https://github.com/spring-cloud-samples/authserver
https://github.com/spring-cloud-samples/sso
The first is an OAuth server that generates JWT tokens upon authenticating the user. The second is a resource that is being consumed. The resource relays the authentication of the user to authserver as per the OAuth spec.
All seems to work very well, leading me to additional questions:
In the authserver, during authentication, how can I get access to the clientId and clientSecret?
Can I determine which values are used for generating the JWT token?
In SSO, how do I get access to the content of the token (for instance, the principal) once the user is authenticated?
Answer to 3): change the method signature to include:
#AuthenticationPrincipal User principal
This way the authentication credentials will be passed to the controller method called by Spring. The other way is through the security context:
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
As for 2), my guess at this point is that to influence the parameters used to compute the JWT token, one needs to implement a custom AccessTokenConverter. If my understanding is correct the default one called DefaultAccessTokenConverter does not allow for this. I welcome any other opinion on this.