Identity Server resource to resource authorize using client credentials and also pass User Identity claims to the second resource - identityserver4

I have a scenario where
User logs accesses a resource (API Resource 1) using Authorization Code flow
(API Resource 1) in turn has to access the data from API Resource 2. The resource to resource authorization uses Client Credentials flow and I need to pass the user identity claims to the API Resource 2 while using the Client Credentials flow.
The API Resource 2 also has support for the Authorization Code flow.
Is it possible to do it in this way? Or am I looking at this differently?
Additional Information
Both the client applications share the same Identity Provider. So, the tokens for both the client applications have same format.

Related

Microsoft Graph - OAuth2.0 flow for React client and spring-boot backend

I am building a React-based SPA that communicates with a spring-boot backend via a REST API. I need the user to be able to log into their Microsoft account on the browser client (the SPA) and I need the backend service (spring-boot app) to be able to query Microsoft's Graph API on behalf of that user.
After reading up on the Oauth2 flows, the authorization code flow (not the PKCE flow, just the regular authorization code flow) seems the most appropriate. The browser client could let the user log into their Microsoft account, retrieve an authorization code, and send the authorization code to our backend service via HTTP request. The backend service (which is trusted and can safely store a client secret) can then request an access token, make requests to the Graph API directly (meaning that the SPA would never need to make any requests to the Graph API), and silently refresh the token as needed.
However, I cannot see any examples of anyone using this flow to access Microsoft's Graph API.
Looking at Microsoft's documentation, it seems like they recommend using the on-behalf-of flow. But this flow requires the browser client to request an access token and then use that to communicate with the backend service (which in turn can communicate with the Graph API). It doesn't make sense to me why the access token cannot be requested on the backend using a client secret. Wouldn't this be a more secure and preferred method than having the client retrieve the access token, as is done in the on-behalf-of flow?
The Oauth2.0 site, recommends that SPAs should either use the authorization code with PKE or the implicit flow, but I do not see an option to use the standard authentication code flow for SPAs. Should I take this as an indication that SPAs should not be using the standard authorization code flow as I described earlier?
Despite not finding a clear-cut example of the standard authorization code flow in Microsoft's documentation for a react frontend + java backend, I tried to go about doing this myself. However, using the #microsoft/mgt-react and #microsoft/mgt-element libraries to do this are not straight forward. For example, the #microsoft/mgt-element notion of a Provider supports a call to retrieve an access token, but doesn't clearly expose the authorization code. If I wanted to do the authorization code flow described earlier, it seems like I would need to use raw HTTP requests, which I know is not a recommended way of accomplishing this.
Summarizing my questions:
What OAuth2.0 flow should I be using: 1) authorization code (access token is retrieved by backend service using client secret), 2)
authorization code with PKE (access token is retrieved by client), or
3) on-behalf-of flow (access token is retrieved by client, seems to be an extension of PKE flow)?
If using the on-behalf-of flow, does the SPA just include the access token in the header (marked as 'bearer') and the backend service just
includes that same header to query the Graph API, or does the backend
service need to request another token before querying the Graph API?
Agree with #ch4mp to call graph api directly in SPA if it's allowed. If not, then I recommend you using on-behalf-flow or client credential flow based on your requirement.
Let's come back to your requirement -- call ms graph api in a springboot api project. First, let's see one of the graph api getting user api. You can see permission types here: Delegated which means call graph api on behalf of the user, Application which means calling api on behalf of the application(your spingboot api project) itself. If you want to call api behalf of the user, then you have to use on-behalf-of flow. This is because the api project which will be considered as a daemon application, so the project itself doesn't have a UI page to let users enter username/password to sign in and get authenticated.
You can certainly use ROPC flow which have to pass the username/password to api but I really think it unsafe, so I don't recommend.
If it's not necessary for you to call graph api on behalf of user, you can certainly take client credential flow into consideration. But pls note here, application type api permission is a "large" api permission which always have name like User.ReadWrite.All, Mail.ReadWrite.All and it always means the application can not only query user information but also be able to modify user information.
If you want to use on-behalf-flow, then you may review this answer and it explained the whole progress...
I would use authorization-code flow (with PKCE) to get an access-token and then refresh-token flow to "maintain" this token, both from client.
Authorizing the request to your resource-server with this token only makes sense if Microsoft authorization-server is your main authorization-server. Otherwise (user also logged in with an authorization-server of your own or not using OAuth2 betwean React and backend), you can still send Microsoft access-token in request body.
In any case, when issuing requests in the name of the user from the backend, do as you suggest: just set the access-token sent by the client as Bearer Authorization header (token is retrieved either from Spring security context or request body). Backend fetches a new access-token (using client-credentials flow) when issuing requests in its own name (without the context of a user).
Side note: have you considered calling Microsoft API directly from React client? If you don't have to store the result of that call on your resource-server (i.e. call graph API to display data and store only what user selected from that data), that would save quite some latency on the client and costs (network and CPU) on the backend.

Spring security OAuth2 new Authorization Server with PKCE with React JS front end

My application is mainly based on spring boot micro services. Currently it uses OAuth with password grant_type which is deprecated in the latest spring security authorization server release. For receiving JWT token, it stores client id and client secret in React JS frontend which is not secure and not recommended. Users need to register to access certain resources and application maintains login credentials in mysql DB
I am trying to upgrade spring security and want 'account service' to act as authorization server to issue JWT tokens.
Am I correct in my understanding that I need to use authorization_code grand type with PKCE?
If I use PKCE then I do not need users to provide passwords while registering, is that correct? Storing only username/email should suffice because users just need to pass client ID and code_challenge to get authorization code?
Am I correct in my understanding that I need to use authorization_code grand type with PKCE?
The newest version of Spring Security mode introduces a new project for the Authorization server in the scope of Spring Security:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.3.1</version>
</dependency>
The authorization server from spring implements OAuth2.1 where as you mentioned, both PASSWORD and IMPLICIT grant types were removed comparing it to OAuth 2.0.
Gran types supported in OAuth 2.1: 1
Authorization code + PKCE
client credentials
device grant type
OAuth 2.1 provide authorization code + PKCE grant type but it's a little bit different from the previous.
"The key difference between the PKCE flow and the standard
Authorization Code flow is users aren’t required to provide a
client_secret. (...) In place of the client_secret, the client app
creates a unique string value, code_verifier, which it hashes and
encodes as a code_challenge. When the client app initiates the first
part of the Authorization Code flow, it sends a hashed
code_challenge."
2
That type of grant type is recommended for SPA application so if you want to use the newest version of spring security you need to use it, because e.g. client credentials are reserved for machine-to-machine communication when one service needs to communicate with another service without of user's knowledge.
If I use PKCE then I do not need users to provide passwords while registering, is that correct?
Users need to authenticate themselves and that's a part of this grant-type flow.
Storing only username/email should suffice because users just need to pass client ID and code_challenge to get an authorization code?
ClientID and generated code_challenge (should be generated by the client) is something that identifies the client not the resource owner, so user while authorized shouldn't provide this type of info.
Authorizing client request
With OAuth2, clients (your React app) must authorize requests to protected resources, that is provide an access-token as Bearer Authorization header.
When acting on behalf of a user, clients should use authorization-code flow (with PKCE) to fetch such an access-token from authorization-server.
Also, use an OAuth2 client library in your React app. It will help you to:
redirect users to authorization-server
handle redirection back from authorisation-server with authorization code
exchange authorization code for tokens (access, refresh and ID)
Some libs even handle:
access token silent refresh before it expires
request Authorization to configured routes (add access token as header)
automatically trigger login when a user tries to access protected parts of the app.
I have not enough experience with React to recommend a specific lib, but you can search with "OpenID", "OIDC" or even "OAuth2" keywords
Configuring spring REST APIs
REST APIs secured with OAuth2 are "resource-servers". You can use spring-boot-starter-oauth2-resource-server directly as done in the first of those tutorials, but it is quite some Java conf.
Instead, you can use one of the spring-boot starters from the same repo. They are thin wrappers around spring-boot-starter-oauth2-resource-server with sensible defaults and most security conf from properties:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<!-- replace "webmvc" with "webflux" if your app is a servlet -->
<!-- replace "jwt" with "introspecting" to use token introspection instead of JWT decoding -->
<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
<!-- this version is to be used with spring-boot 3.0.0-RC2, use 5.x for spring-boot 2.6.x or before -->
<version>6.0.5</version>
</dependency>
#EnableMethodSecurity
public static class WebSecurityConfig { }
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,ressource_access.some-client.roles
com.c4-soft.springaddons.security.cors[0].path=/some-api
Configuring the gateway
Basically, nothing to do in regard to authentication and OAuth2: inbound requests to secured resources should have an authorization header already and resource-servers will respond with 401 if authentication is missing or invalid (expired, wrong issuer, ...) or 403 if access is denied (valid identity but not allowed to access that resource)
authorization-server
Any OAuth2 authorization-server would do, but you might choose an OIDC implementation.
Authorization-server will handle users registration, login and logout. It will issue access, refresh and ID tokens, using mainly:
authorization-code flow for clients acting on behalf of a user
client-credential flow for trusted programmatic client acting in their own name (not on behalf of a user)
refresh-token: if offline_access scope is requested when authenticating (with any flow), a refresh-token is returned in addition to access-token and can be used to silently get a new access-token when current expires (or just before it does)
You can use Spring authorization-server framework to build your own authorization-server, but could also prefer to pick one "off the shelf": there are plenty out there with a lot of features implemented
connect to LDAP and "social" identity providers (Google, Facebook, Github, etc.)
enhance security with multi-factor authentication
provide with admin UI for stuff like user roles or tokens content
...
And this either on premise (Keycloak is a quite popular sample) or SaaS (like Auth0 and many others: almost any cloud provider has its own solution).

Spring OAuth2 Single Page Application Integration to Azure

I have been tasked with integrating Azure Active Directory Authorization into one of our applications and have tried out some of the samples with relative success.
I have a Javascript SPA application (GoogleWebToolkit) that communicates with a Spring REST (not Boot) API. The Rest API is currently secured with Spring Security and login URL username/password etc.
I want to change this to use Azure OAuth2.
Being new to OAuth2 I'm trying to figure out if I should be using either of the following Spring options.
With this option all the configuration is done at the server side, client id,secret
If I do a href from the SPA front end to 'oauth2/authorization/AzureAD' URL, its sends a redirect to the Azure Login page, allows authentication and redirects back to what redirect URL I enter into the Azure AD console configuration. This works to a degree but trying to extract the token and pass it back is not working so far.
http.oauth2Login()
.clientRegistrationRepository(clientRegistrationRepository())
.authorizedClientService(authorizedClientService())
.authorizationEndpoint()
.authorizationRequestResolver(
new CustomAuthorizationRequestResolver(
clientRegistrationRepository(),
#Bean
public ClientRegistration clientRegistration() {
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId("AzureAD");
builder.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST);
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
........................
or
I haven't fully tried this option yet, but I think it involves doing the authorization directly from the SPA javascript front end, put all the values for the client id/secret into the javascript FE etc, and then passing the once acquired token via the Auth header for validation by the server side. Like at https://www.baeldung.com/spring-security-oauth-jwt
.oauth2ResourceServer()
.jwt()
.jwkSetUri("https://login.microsoftonline.com/common/discovery/v2.0/keys");
Could someone confirm where I should be using Option 1 or 2, and if I am understanding things properly?
Your understanding is correct in option 2. As per above scenario, let’s consider Front End Application which is Single Page Application (Java Script) to be OAuth Client App to orchestrate the process of obtaining access token and then grant access to resources from Spring back-end application.
So, here client Application need to be registered in Azure AD to acquire the access token secured by Azure AD.
We recommended MSAL libraries which helps to acquire tokens from the Microsoft identity platform and handle token in many ways to authenticate users and access secured web APIs.
Both the applications (front end and back end) need to register in Azure AD based on the scenario.
Update client-id, tenant-id, redirect URI to front end application configuration file based on application registration in Azure AD.
Back-end application also need to be registered in Azure Ad to secure by Microsoft Identity which can then define the delegated permissions(scopes) your API exposes.
Then business logic needs to add in back-end application to determine what is allowed or prohibited based on these scopes in access token.
To authorize the client request in Spring application:
Users will start by authenticating with a username and password in front end application.
Once authenticated, the client will receive a JWT representing an access token.
The client will include the access token in the authorization header of every request to a secure endpoint.
The resource server will validate the access token and determine if it has the right permissions, using the information within the token.
In this case, Spring serves as resource server and not acquiring any token in the back-end application .
Security Configuration in Spring provides numerous methods to add filters to the HTTP request to authenticate each request.
Here,
http.cors() will allows Cross-Origin Resource Sharing (CORS) checks to succeed.
All the requests need to authenticate before passing to the application(controllers).
Spring application serve as a resource server and authentication should be provided via JWT access tokens and further validate the roles and scopes in the application’s controller using #AllowedRoles annotation.
Our JWT access tokens are signed by Azure AD and application should check if their signature is correct. Azure AD has an endpoint with the public key to do so, which need to configure in spring application.
Also, as mentioned, we will need access token to call the protected back-end application because contents of the token are intended for the resource (back-end API) to perform authentication and authorization.
To validate the token, you can search the keys endpoint in the discovery document and then provide this JSON web key (JWK) endpoint straight away where JWK URI can be found.
# application.properties
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://login.windows.net/common/discovery/keys
Note: The flow would be same to get the access token while integrating with Azure AD. i.e in Spring boot or in spring.

How to use Azure AD access_token and id_token

I have registered two applications in Azure AD, a .Net core web API and a single page react application. I configured these applications to get the id_token for the react client application and an access token for consuming the web API when the user signs in to the client application. I need to send user-specific information to my API when the user signs in (I need to get a unique id from the token to identify the user). Some document says we can't send the id_token to the API since it is issued for the client application. and some says we can't send the user-specific information via access token since it should be used for authorization purpose only.
Is there any other way to solve my problem?
In the context of Open Id connect, is it ok to send user-specific information via access token? I want a unique id from the token and store it in my system to identify the user. if it is ok to use the access token, Which claim is best suited for this purpose (sub or oid)?
You are right that you should not send the id_token to the API. One option is to include the necessary user information as claims inside the access token. Alternatively you could try to ask AzureAD for the user details when the API receives the access token. Azure for example provides the UserInfo endpoint for this.
See this page Microsoft identity platform UserInfo endpoint

Identity Server 4 with WebAuthN - using GrantType (FIDO 2.0)

I'm using Identity Server 4 to authenticate users with WebAuthN (https://w3c.github.io/webauthn/).
I have multiple clients that that hit an api client. My api client is responsible for deciding which auth provider to use, passing data (server to server, server to external api) and orchestrating the auth process.
One auth provider we are using that we own is identity server 4 and this is where we are implementing WebAuthN.
I'm not sure which is the recommended way to implement this in Identity Server 4. I'm down to 2 options
Create an API endpoint on identity server to authenticate to users credential
Create an extension grant type and call the TokenEndpoint API using the new grant type (my extension grant type would be a mix of the built in Hybrid grant type followed by the WebAuthN code).
Are both ways valid from a security standpoint (not opening up a hole) and fit with ID4 or is there another way?
I've recently done some work on implementing this, but for second-factor only at this point.
Long story short, it needs to run in the context of the end user's browser (given that it's a JavaScript API) so really it needs to be built into the sign in flow via the authorize endpoint.
For example (assuming no local client or IDP sessions already exist):
User visits client application
Client redirects to authorize endpoint
Authorize endpoint redirects to interactive authentication UI which then decides what method to use
Do the WebAuthn challenge, validate the result and establish a session cookie
Redirect back to authorize endpoint
Issue tokens and redirect back to client
You'll also need to provide a way for users to register their authenticators. The resulting credentials are tied to the site origin so this must be done within your identityserver4 implementation - the same application that will be doing the challenging.

Resources