I'm trying to get service-to-service authentication working in Azure AD. I have it working when the two services (webapps) are running locally against an Azure AD app registration. But when the webapps are running in Azure (against the same Azure AD app registration), it doesn't work.
I've created two Azure App Service webapps (which are ASP.NET Core Web API projects) - one acting as the client and the other the server. The bit that breaks is the client webapp, where it requests an access token from AzureAD. It only breaks when requested a token with a custom scope. This same 'custom scope' token request works fine from a local webapp though.
In Azure, I've created an 'App Registration', and given it a custom scope called 'bob'...
In the client ASP.NET Core webapi app, I've added the Azure.Identity nuget package, and am getting a token like this...
var tokenRequestContext = new TokenRequestContext(new[] {scope});
token = await new DefaultAzureCredential().GetTokenAsync(tokenRequestContext, cancellationToken);
(where the scope variable matches the name from the screenshot above)
Locally, this works fine and returns a token.
In Azure, I get this exception:
Azure.Identity.AuthenticationFailedException: DefaultAzureCredential failed to retrieve a token from the included credentials.
- ClientSecretCredential authentication failed: AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope api://<guid>/bob is not valid.
(I've removed the GUID from that snippet)
When running this locally and in Azure, I'm setting the AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID environment variables to the same value. I don't understand why it would work differently locally than in Azure, given these environment variables are the same.
Note that my intention is to use a Managed Service Identity instead of setting those environment variables. But for the time being, by using those environment variables both locally and in Azure - both should be using the same "ClientSecretCredential" authentication - so I'd expect the same results.
There are 2 parts of the answer:
Azure.Identity is currently meant to be ONLY for the native Azure Services SDK using new Azure.* client libraries. In your case, you are trying to use it for your custom web app auth with custom scope which is not officially supported or documented. For regular auth flow (like in this case Client Credential Grant for example) You should be still using MSAL, OR for easier integration with asp.net core apps, Microsoft Identity Web.
NOTE: Specifically for Client Credential Flow, it only allows .default scope. There is an open UserVoice and another thread for workaround.
Now coming to your problem of why it's is not working in Azure.Identity DefaultAzureCredential (regardless of the fact it's not officially supported). I suspect at your deployed Web App, it's probably one or more context missing (IDENTITY_ENDPOINT or AZURE_AUTHORITY_HOST would be my wild guess looking at code). But no idea unless we do little trial and error (again, I would only want to do it for experimental purpose, not in a real production application due to lack of official support). The DefaultAzureCredential attempts to authenticate via the following mechanisms in order. In your local machine, it might be able to get the required context from one of mechanisms down in the chain (like VS or CLI) whereas in the deployed app, those are simply non-existent.
While explicitly stated - you can use the .default claim as hinted at here: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#the-default-scope.
This will let you generate an access token for your API but it will not have any other scopes for you to verify.
Related
I am writing code to connect to power bi via TOM (Tabular Object Model) as opposed to the Rest API. Apparently the same authentication token can be used for both the REST API as well as TOM connectivity. As per here https://learn.microsoft.com/en-us/analysis-services/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo?view=asallproducts-allversions
In a deployed environment that uses managed identity the token works successfully for both, however in my local dev environment it fails on the Server.Connect to TOM (as per below) with an Unauthorized error.
The TokenService is just using the DefaultAzureCredential which makes use of the Azure CLI credential available once the dev does an "az login". Once again this works seamlessly for the REST API but fails against the XMLA endpoint on Server.Connect.
Wondering if anyone else has managed to get this to work? We do not want to use application based authentication as that significantly complicates things.
Thanks
I secured my ASP.NET Core Azure Function App by modifying the configuration in Startup.cs and calling the Microsoft.Identity.Web's AddAuthentiction and AddMicrosoftIdentityWebApi extension methods on the services collection object (similar to the approach used in the AzureFunctions example in the Tests directory of the GitHub repo of Microsoft.Identity.Web). This allows me to securely call the Azure Function API from my Blazor Server app using Microsoft Identity Platform. The Azure Functions API does not call any downstream api.
This approach works perfectly fine without the need to enable the Authentication option under Function App - Setting in Azure Portal and specifying an identity provider there and linking it to an Azure AD app registration.
Does somebody know what does enabling authentication and adding an identity provider under settings of the Function App in the Azure Portal do compared to the manual configuration in Startup.cs? If I understand correctly, it does the same thing but implicitly instead of explicitly in the Startup.cs.
That option, sometimes referred as "Easy Auth" enables an additional container (or program) that will validate the token, so you don't have to. Request will first go to that middleware application and then, if validation passes, will go to your app.
For details see the docs page: https://learn.microsoft.com/en-us/azure/app-service/overview-authentication-authorization
That option is common to the webapps and function apps. The code runs separately, so it's not part of your application middleware chain.
I've created a new Blazor app using the Visual Studio template adding B2C using the wizard during the project creation.
All works great with authentication. I can sign in using my favorite identity provider and receive the id_token. I don't know where I can get the id_token, but I can see the claims in my user identity.
What I need help with is how do I take the information in the claims to acquire the access token. I need this token to call my endpoints.
This seems like it should be straightforward and a common thing, but I can't seem to find any good examples.
In a normal MVC app, I can get this through the ConfidentialClientApplicationBuilder.AcquireTokenByAuthorizationCode but that doesn't work in Blazor (unless I'm doing something wrong).
I've tried this: https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens
I think it'll work. How do I get "code"(id_token) in my blazor app? It's what is decoded behind the scenes and all I can find are the claims resulting from decoding the "code".
I've used the azure's "Run user flow" to access an example id_token("code") and pasted it into my project and made the call in the link above and it seems to work. I'm running into permission issues, but it's at least a successful call.
Maybe if I can just get access to the id_token I can make it work from there?
This seems like a client side app, similar to a SPA. In which case you must use the implicit flow, where the response type is “id_token token”, and returns an id token and access token to the browser in one call. This isn’t an exact answer, but only our MSAL.js library can make this type of call, but Blazor seems to use C#, and msal .net does not do client side auth calls. acquireTokenByAuthCode() would work client side as long as you register the app as a native app, so a secret is not required.
First of all excuse my bad english.
I'm a newby in oauth2 and I'm trying to setup an authorization server with JWT tokens.
The server is running in a Owin self-hosted environment.
At this moment I've setup the token generation and it seems to work properly, I've also setup the refresh token provider and it seems to work (but it's just a minimal implementation); I didn't change the RefreshTokenFormat in the OAuthAuthorizationServerOptions leaving it to default (I don't know what is the default format), so the access-token is clearly a JWT token and the refresh token is something else.
All of this seems to work correctly, but I will need to run this authorization server in a microservices environment, so the authorization server service might be moved at any moment from one machine to another, so it needs to be stateless or at least to save needed informations on a shared storage (DB) or replicated local storage (I'm on Service Fabric) or some kind of distributed cache.
Testing I noticed that if I generate a refresh-token on a machine and then I try to use this refresh-token on another instance of the authorization server (on another machine) to get a new access-token, it fail with a generic invalid_grant error. My guess is that the auth server just keeps some token-related information in memory but I don't know exactly what and how.
I also would like someone to point me in the right direction to solve this issue.
Thank you very much.
I solved the situation using a JWT token also for the refresh token.
This way the authentication server seems to be completly stateless.
I followed this Microsoft Azure Mobile Service Authentication Tutorial, to try to add a server authentication function for my Windows Store C# app. However, after completing every step, when I run my app, it showed that the application cannot connect to the service.
I found this useful blog tallking about troubleshooting Azure Authentication issues in Azure Mobile Service. To troubleshoot, I type the link in the firefox web browser: myServiceUrl/login/aad, but I receive the error response:
Authorization has been denied for this request.
I also followed the same tutorial to test with Google Log in. It turns out to work properly. And when I type the link: myServiceUrl/login/google, the web browser directed me to the google log in page, unlike the Unauthorization error message when I type in myServiceUrl/login/aad.
Although google log in works out fine, but it is desired for us to use Azure Active Directory authentication. Could anyone tell us what could possibly be wrong? Any troubleshooting suggestions are also appreciated. Thank you.
The "Application cannot connect to the service" error comes from whenever the Web Authentication Broker in Windows receives an error response from the resource it is trying to reach. There are a couple of issues that can cause this, and I'll try and address the most common ones.
I noticed the tutorial you linked to is for the .NET backend. If you are using the Mobile Services .NET backend, there is an extra step required to configure the AAD server flow, and it's a common cause of the issue being described. In the tutorial, it's under the title "Configure your .NET mobile service for AAD login." On the backend project, you will need to install the Mobile Services .NET Backend Security Extension NuGet package. Then, in WebApiConfig.cs, you will need to include
options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));
This allows the runtime to use the server flow in addition to the client flow (leveraging the Active Directory Authentication Library) which was first released with the .NET backend.
Pending that, or in the case of the Node runtime, the next thing to do is check the AAD configuration. In the AAD portal, make sure that your application registration uses your mobile service's /login/aad endpoint for the resource URI. It must match exactly the value provided in the Mobile Services portal. This should also be one of the redirect URIs if you are using the Node backend. For .NET, you would use the /signin-aad endpoint for the redirect URI instead.
You should also check that you have copied the Client ID from the AAD registration and pasted it into the Mobile Services portal's Identity Tab. For completeness, the "Allowed Tenants" field should also be filled out, but I don't believe it is the cause of this issue.
Lastly, if your AAD tenant is federated with ADFS, then there is a wide range of issues that could lead to this. The biggest case comes from the WAB needing to be configured for Enterprise Authentication. This typically only causes problems when the device is domain joined / on the corporate network. That behavior is a known bug for the Mobile Services Windows Store SDK, but there is a workaround available. Glad to provide that if needed.