Refresh token flow in Azure Active Directory with a federated Google user - azure-active-directory

I have set up an Azure Active Directory tenant with direct federation to Google. Next to that I have a .NET core web application using the OIDC code flow for getting both id_tokens and access and refresh tokens. The access token is used to call my API which is working fine.
Now the problem is whenever I use my refresh_token to get a new access_token I receive a new access_token, but no refresh_token. So I can only refresh once.
I only have this issue when authenticating with my Google account using direct federation. When I authenticate using a tenant native account I can refresh unlimited.
We have two multitenant Azure AD app registrations as described here. One for our single page application and one for our API. In our single page application backend we use the OpenIdConnect middleware to authenticate against Azure AD. Note that we are not using the common endpoint, but the tenant specific endpoint because otherwise direct federation does not work. We can reproduce this issue by intercepting the refresh token in the OnTokenResponseReceived event of the OIDC middleware and initiating the refresh flow as stated here (by using Postman for instance). The response is successful, but does only contain an access token, no refresh token.
Is this behavior by design?

Related

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.

ReactJs FE and Django Rest Services with Azure AD for authentication & Authorization

I'm having a Frontend application built in Reactjs connecting to Azure AD using msal for authentication. After authentication, the user needs to click a button which calls a Django rest API which is also authenticated using Azure AD.
React FE and Django connects to two separate App registrations in Azure AD. Even thought 1) FE is added to Django's App registration as known client 2) Django is exposing the API and the scope is given consent.
When the authenticated FE sends requests to the Django Rest service with Bearer token,
it fails to authenticate the request saying 'invalid token'.
I'm able to authenticate FE and Django rest service separately but authenticated FE is not able to connect to the Django Rest service. Please share your thoughts on what else needs to be checked or any solutions.
Please check if any of these configurations can be worked around
Check if you have given your react app’s URL in the redirect URL in portal and code , so that once the Azure AD validates the user and it’ll return back to your react app with ID Token.Also, enable Access Token and ID Token.
Check if you have created a scope for your web api (in Azure Portal > Your API > Expose an API). Then configure it on your client app on the API Permissions menu tab. Then add it on your scopes collection in code settings.Also, add grant admin consent for that API permission.
Check the manifest of your azure ad app: Below value is probably null or one, should be two: If you are using v2.0 endpoint,
"accessTokenAcceptedVersion": 2,
If you are using v2.0 endpoint, the scope should be api://{server_client_id}/.default.
In the code setting.py for your application, you'll need to provide the authority to which your web app delegates sign-in. (ex: authority: 'https://login.microsoftonline.com/(your tenant id>',)
auth: {
clientId: '232a1406-b27b-4667-b8c2-3a865c42b79c',
authority: 'https://login.microsoftonline.com/e4c9ab4e-bd27-40d5-8459-230ba2a757fb',
//
}
When we perform a token validation, Check your jwt token in http://jwt.io
Audience: The token is targeted for the web API.
"aud" value that is being generated for JWT token by azure is also controlled by "accessTokenAcceptedVersion" property in AD application manifest.(see if issuer or iss has v2 to confirm as v2 endpoint )
If you have set the access token accepted version to 2, then the client id and audience needs to be same (i.e. no need to write api:// in audience)
Note that Implicit flow is the only flow supported for SPA. Authorization code flow is intended for webapps, mobile and desktop apps but not for SPA.Please refer this document
References:
See how to configure Azure AD and how to determine the settings for
django-auth-adfs.
You can check this and find your use case scenario.
Check v2-supported-account-types for authentication-flows
Check OAuth2.0 On-Behalf-Of flow

Azure AD with Single Page Application and ASP.Net core web api: how to access all relevant tokens?

Our application is an Angular SPA with ASP.Net Core Web API. The identity is provided by Microsoft Identity Platform (Azure AD) and authentication is provided by the same. The authorization is done in Web API basis "Application Roles". These "Application Roles" are held in the Azure AD directory (defined in the Application's manifest and assigned on the tenant domain to users).
The Angular SPA receives the tokens from Azure, as per these instructions. The relevant tokens that are issued are: an AccessToken for my Web API (following these instructions), an AccessToken for calling Graph API (following the same instructions) and an IdToken that includes the "Application Roles" as roles claim (this id token seems to be included automatically once roles have been assigned).
The problem I face is that I need to pass concurrent tokens to my Web API, but with the HTTP interceptor I can only include 1 token in the header request. For example, I need the first AccessToken to proof authentication to the Web API and I need to include the IdToken such that the Web API can perform authorization.
Q: How can I call my Web API with multiple tokens, when these tokens are all issued to the SPA and need to be included in the HTTP call to my Web API?
No matter whether you want to get Microsoft Graph data, the way you used to get Application role is incorrect.
An id token cannot be used to perform authorization for your Web API application. You have to use access token. See this answer to learn about the usage of id token and access token.
So you have to use an access token rather than id token.
In this case, you configure the app roles in the Azure AD app which represents Angular SPA (the front).
In fact, you should configure the app roles in the Azure AD app which represents ASP.Net Core Web API (the backend). Then you can get the "Application Roles" as roles claim in the AccessToken for your Web API.

How to configure a WebApp & WebApi with different AAD App IDs?

I currently have two app services
Web App (Asp.net core 2 w/ front end in react)
Web Api (Asp.net core 2)
Note: Both are configured with different Azure active directory app id.
user signs into Web App and retrieves a token for it's own appId/ClientId/ClientSecret stored in tokencache.
from the WebApp, the user wants to talk to a WebAPI but needs to get a token since it's protected with AAD as well but it's a different app id/client id/client secret.
Problem:
When I try to do a AcquireTokenSilentAsync() for the web api, I get an error throwing that I the token is not in the cache?
It also seems that with depending if your using AAD v2.0 or v1.0 will determine if the web app and web api can have different app ids. So it seems like i would have to use AAD v1.0. With Asp.net core 2, it's not clear to me what OpenIdConnect is using or configured to use under the covers.
Question:
It's not clear to me why the acquire token silent async didn't work and failed. Does that only look for the token in the cache; otherwise it fails?
Is it possible to configure the token from web app to have permission to access web api resources. I notice that in the azure portal, you can selected resources like microsoft graph, but I don't know how you would associate a custom API. In my case, I want to get it running on my local machine before I move it all to azure.
If the web app token does not have permission to access the web api, do i need to do another login authentication with the user even thou both are within the same tenant?
Any Advice appreciated,
Derek
Yes, AcquireTokenSilentAsync will look into the cache, and see if it can find tokens. If it does, it will check to see if the access token is still valid and return that back. If the token is expired, it will use the refresh token to fetch a new access token and return that back. When this call fails, it's an indicator you need to perform an AcquireTokenAsync (which will likely show UI in the case silent already failed).
Yes, you can associate a web app to get tokens for your own custom web API. I'd recommend using Azure AD v1.0 (register the app in the Azure portal, ADAL library). You'll need to register the two apps (web app and the api), both will be type web app/api. In the API, you can register an App ID URI which will act as the resource identifier for this API. In your web app, you'll want to go into the Required Permissions, and add the Web API you have registered as a permission. Then in your web app, you'll need to use the ADAL library (alongside an OpenID OWIN middleware) to acquire a token for the resource as specified by the App ID URI field. Here's a code sample that implements the exact scenario you're describing (Web App/API in ASP.NET Core).

Identity Server 4 (with external Azure AD auth) token is not valid in Graph API

I am switching my application from Azure Active Directory authentication to authentication with Identity Server (using Azure AD as external auth). The authentication and authorization part is implemented and my web API successfully validates token and give me what I'm asking.
Our application also uses external APIs, such as Graph API and SharePoint Online which require Azure AD token. E.g. when I go to https://graph.microsoft.com/v1.0/me from my JS application with token that I get back from Identity Server, Graph API response is
401
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "ce7651bb-5dc4-49e9-90ff-02df440ed4ad",
"date": "2017-08-11T08:53:12"
}
}
}
I expected that because Identity Server is giving me his token, and not passing the existing token that is provided by Azure AD. I copied all the claims from Azure AD token into identity server token, but no changes.
What would be the right approach to enable my application to continue using APIs which require Azure AD token?
EDIT:
What I'm hoping for is this.
Click login button on Js (or any other client app)
Redirect to Identity Server login screen
Click on Azure AD external auth
Redirect to Microsoft login page and enter your credentials there
Redirect to Identity server app
a. I started Fiddler and see that "Microsoft" redirect to {IdentityServerAppUrl}/signin-aad (I suppose this is because I configured CallbackPath property on OpenID Connect options). This request carry a cookie idsrv.external. I'm not sure but I think inside is access token from Azure AD. I don't know how to decode this. I tried with base64, but it is not working.
b. When this request is finished redirect is made to {IdentityServerAppUrl}/account/ExternalLoginCallback. In this action method I check with debugger all fields and data in request but I can't find token from AAD. I'm hoping to get token and put it in additional calims.
Identity Server app redirect to JS client app with its own token and additional claim that contains Azure AD token that is valid on graph API and SharePoint.
First I would like to locate Action method or middleware that handle {IdentityServerAppUrl}/signin-aad?
Second, is there any way to get token from Azure AD or any other external provider inside {IdentityServerAppUrl}/account/ExternalLoginCallback Action method?
Be aware that I'm new to this kind of stuff and maybe I'm totally wrong with this thinking.
I manage to do Azure AD authentication without Identity Server, but know we have request to have multiple external providers and I'm hoping to handle all authentication in one app. If one day I get request to have additional external provider I need to add to just in one place.
You need to retrieve an access token from AAD for the Graph API - how that exactly works, check the Microsoft documentation.
Once you have that access token, you can return it as a claim in either the IdentityServer identity or access token (depending if you want to make it available to your front or back-end).
You can also try that first in a simple MVC app to remove the moving partsy - and once you have the AD part working, move your code to the app using the identityserver middleware.
I am also looking for an answer to this question. However, I think it should work a bit differently. IdentityServer gives you a JWT that you can use to authorize to the recources that make up your app. E.g.: yourAPI-1 and yourAPI-2. With the JWT you can pass on the identity. Microsoft Graph is an external resource. Therefore we would need the access token form the Graph API as a claim or external resource, same way as you'd receive an access token for an internal resource.
I would guess that there should be a way of forwarding whatever information you get from the identity provider (Azure AD) to IdentityServer for your client (JS app) to pick up. I am facing the same problem here.
There is another thread about this topic that caught my attention which I will look into. It requires to build your IdentityServer from the source with a few modifications: ASP.NET Identity (with IdentityServer4) get external resource oauth access token
I will let you know what the outcome is and push it to a git repo that you can use if it works:

Resources