I'm struggling with authenticating towards an Azure Mobile Service (.NET backend) via Azure AD. I've been following this tutorial: https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-how-to-configure-active-directory-authentication/
The authentication to Azure AD itself is successful (result.Status == AuthenticationStatus.Success), but I get HTTP 401 at MobileService.LoginAsync.
Mobile Service Azure AD app config
Sign-on URL: https://contososervice.azurewebsites.net
Client ID: c710fe9b-4dd2-406b-ae68-ea5825c2c103
App ID URI: https://contososervice.azurewebsites.net
Reply URL: https://contososervice.azurewebsites.net/.auth/login/aad/callback
Native client Azure AD app config
Client ID: d79fea3f-2357-4797-9be8-48d630f6e1a3
Redirect URIs:
- https://contososervice.azurewebsites.net/.auth/login/done
- ms-app://S-1-15-2-4177921760-2458829842-3328621796-4043898254-238447652-453539330-2174227773
Permission delegated to ContosoService
Azure mobile service authentication config: advanced mode
Client ID: c710fe9b-4dd2-406b-ae68-ea5825c2c103
Issuer URL: https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47
Mobile service web.config
<add key="ida:Tenant" value="contoso.onmicrosoft.com" />
<add key="ida:Audience" value="https://contososervice.azurewebsites.net" />
Mobile service authentication setup
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
}
UWP client
string appIDUri = "https://contososervice.azurewebsites.net";
string clientID = "d79fea3f-2357-4797-9be8-48d630f6e1a3";
AuthenticationResult result = await _authContext.AcquireTokenAsync(
appIDUri,
clientID,
WebAuthenticationBroker.GetCurrentApplicationCallbackUri());
if (result.Status == AuthenticationStatus.Success)
{
IsUserAuthenticated = true;
UserData = result.UserInfo;
success = true;
JObject payload = new JObject();
payload.Add("access_token", result.AccessToken);
var user = await ServiceClient.ServiceClient.MobileService.LoginAsync(
MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,
payload);
}
I actually managed to solve this.
Remote debugging the Mobile Service via Visual Studio has helped, because Microsoft.Azure.AppService.Authentication tracing showed that:
A browser request posted the token to https://contososervice.azurewebsites.net/.auth/login/aad/callback, which was successfully processed
My client app posted the token to https://contososervice.azurewebsites.net/login/aad, which didn't work.
It took me a while to understand that the URL the tokens are posted to is actually identical to the appIDUri in the code, and because that identifies the resource, too, I had to change the corresponding App ID URI setting in Mobile Service Azure AD app config.
Thus I had to change both appIDUri and App ID URI in Azure AD tohttps://contososervice.azurewebsites.net/.auth/login/aad/callback
and it works now.
Related
I've created a web api which requires authorization and is deployed to an Azure Web App. I also have a Blazor Server app which requires Azure AD authentication.
When I run the Blazor Server app from within Visual Studio it can get a token and successfully call the web api deployed in Azure.
However, when I deploy the Blazor Server app to an Azure Web App it gets a 401 error when it calls the Web API, despite the fact that it worked from Visual Studio.
This is how I am setting the token prior to the Web API call
var accessToken = await _authRepo.PrepareAuthenticatedClient();
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
also including a catch of the exeception
#inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
catch (Exception ex)
{
ConsentHandler.HandleException(ex);
}
This procedure gets a token for the logged in user for the web api scope:
public async Task<string> PrepareAuthenticatedClient()
{
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { _WPScope });
return accessToken;
}
This is the code in the startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "api://xxxxxxxxxxxxxxxxxxxxxx/allaccess" })
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
How do I set this up in Azure so that it works the way it does in Visual Studio?
Please try these:
After decoding the token , if you see issuer url with v2 endpoint
make sure to change accesstokenaccepted version to 2 in manifest in
azure ad portal , if iss value has v1 endpoint change in manisfest
to 1.
Also if above is not the cause, see if audience i.e; aud claim is equal to client id. Else try changing the scope by not including prefix api://.
And also please make sure the api permissions are granted consent.
I have an existing Asp.net MVC Web API Project and my Startup(OwinStartUp) file code has
public void Configuration(IAppBuilder app)
{
WebApiConfig.Configure(app);
}
I have to build a new API which has to Authenticate Azure AD B2C token and read the claims for further processing.
How to can I achieve this using middleware? I am not able to succeed using UseJwtBearerAuthentication
See this sample app that uses OWIN w/ B2C.
More specifically this code:
public void ConfigureAuth(IAppBuilder app)
{
TokenValidationParameters tvps = new TokenValidationParameters
{
// Accept only those tokens where the audience of the token is equal to the client ID of this app
ValidAudience = ClientId,
AuthenticationType = Startup.DefaultPolicy
};
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
// This SecurityTokenProvider fetches the Azure AD B2C metadata & signing keys from the OpenIDConnect metadata endpoint
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(String.Format(AadInstance, Tenant, DefaultPolicy)))
});
}
I am using below code to authenticate default user in my Azure trial account.
static void Main(string[] args)
{
GetTokenAsync().Wait();
}
static async Task<string> GetTokenAsync()
{
string Tenant = "mytest.onmicrosoft.com";
string Authority = "https://login.microsoftonline.com/" + Tenant;
string GatewayLoginUrl = "https://login.microsoftonline.com/something/wsfed";
string ClientId = "something";
Uri RedirectUri = new Uri("http://something");
AuthenticationContext context = new AuthenticationContext(Authority);
PlatformParameters platformParams = new PlatformParameters(PromptBehavior.Auto, null);
AuthenticationResult result = await context.AcquireTokenAsync(GatewayLoginUrl, ClientId, RedirectUri, platformParams);
return result.ToString();
}
I want to know from where to get these values:
Tenant
Authority
GatewayLoginUrl
ClientId
RedirectUri
Is this much code sufficient for user authentication using AD?
There are a couple of scenario's when it comes to protecting applications using the Azure Active Directory (See here):
These are the five primary application scenarios supported by Azure AD:
Web Browser to Web Application: A user needs to sign in to a web application that is secured by Azure AD.
Single Page Application (SPA): A user needs to sign in to a single page application that is secured by Azure AD.
Native Application to Web API: A native application that runs on a phone, tablet, or PC needs to authenticate a user to get resources from a web API that is secured by Azure AD.
Web Application to Web API: A web application needs to get resources from a web API secured by Azure AD.
Daemon or Server Application to Web API: A daemon application or a server application with no web user interface needs to get resources from a web API secured by Azure AD.
You mention you have registered a Native Application. I assume you need to authenticate against the Azure Active Directory (AAD from now on) to gain access to a protected web api or web app (scenario #3) so you have to register that one as well.
static void Main(string[] args)
{
GetTokenAsync().Wait();
}
static async Task<string> GetTokenAsync()
{
string Tenant = "mytest.onmicrosoft.com";
string Authority = "https://login.microsoftonline.com/" + Tenant;
string GatewayLoginUrl = "https://login.microsoftonline.com/something/wsfed";
string ClientId = "something";
Uri RedirectUri = new Uri("http://something");
AuthenticationContext context = new AuthenticationContext(Authority);
PlatformParameters platformParams = new PlatformParameters(PromptBehavior.Auto, null);
AuthenticationResult result = await context.AcquireTokenAsync(GatewayLoginUrl, ClientId, RedirectUri, platformParams);
return result.ToString();
}
Tenant is the name of the AAD domain, it seems you got that one right
Authority is "https://login.microsoftonline.com/" + Tenant, so it seems you got that one right too
GatewayLoginUrl is the App Id Uri of the application that you are protecting
ClientId is the Application Id of the native application
RedirectUri is the Redirect Uri of the native application
Application to Protect:
You get the GatewayLoginUrl from here.
Native Application that accesses the Application to Protect:
You get the ClientId and RedirectUri from here.
Other references
You can see a full walkthrough for a native application here
For a global overview of accessing AAD protected applications using a native app see the docs
I am working on a AnguarJS SPA application calling with an Asp.Net WebAPI.
I have registered both the Client as well as the Backend Application on the Azure AD.
My Client/Web Application is registered with the following details:
Sign On URL: http://localhost:93
APP ID URL : http://xyz.onmicrosoft.com/XYZLocalClient
ClientID: 34A721C3-20E4-41D5-9BC1-486A99BF7C26
Reply URL: http://localhost:93
I have given the permissions to other applications (delegated permission) for the client app to access the WebAPI (LocalWebAPI).
My WebAPI has the following setup:
It is using the OWIN Middleware with the startup.cs file as:
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
private void ConfigureAuth(IAppBuilder app)
{
var azureADBearerAuthOptions = new
WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
};
azureADBearerAuthOptions.TokenValidationParameters =
new System.IdentityModel.Tokens.TokenValidationParameters()
{
ValidAudience =
ConfigurationManager.AppSettings["ida:Audience"]
};
app.UseWindowsAzureActiveDirectoryBearerAuthentication
(azureADBearerAuthOptions);
}
It is registered on the Azure AD with the following parameters:
SIGN-ON URL: http://localhost:93/Api/V1/
APP ID URI: https://xyz.onmicrosoft.com/LocalCognia
Reply URLs: http://localhost:93/Api/V1/*
My Web.Config file is:
<add key="owin:AutomaticAppStartup" value="true"/>
<add key="ida:Tenant" value="xyz.onmicrosoft.com" />
<add key="ida:Audience" value="34A721C3-20E4-41D5-9BC1-486A99BF7C26" />
I have also decorated my controller with the [Authorize] Attribute.
Everything seems to be working fine. I am able to authenticate the user and able to access the resources from the WebAPI when I run my application from the Visual Studio 2015 environment (IIS Express).
But as soon as I deploy my application on the IIS Server, using the same parameters, (expect that the application is now on localhost:8087 and with the reply URL for the client app as: localhost:8087), I am getting error as 401: UnAuthroized user on calling the WebAPI.
I am getting the token in the Headers for the WebAPI call, but still getting the error. Not sure of this behavior. Can someone please help on this?
Please use below code in your ConfigureAuth :
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
I have browsed all the tutorials regarding using Oauth to protect WebAPI in Azure active directory online. But unfortunately, none of them can work.
I am using VS 2017 and my project is .net core.
So far what I have tried is:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
ervices.AddAuthentication(); // -----------> newly added
}
In "Configure", I added:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
Audience = Configuration["AzureAd:Audience"],
});
Here is my config:
"AzureAd": {
"AadInstance": "https://login.microsoftonline.com/{0}",
"Tenant": "tenantname.onmicrosoft.com",
"Audience": "https://tenantname.onmicrosoft.com/webapiservice"
}
I have registered this "webapiservice" (link is: http://webapiservice.azurewebsites.net) on my AAD.
Also, to access this web api service, I created a webapi client "webapiclient" which is also a web api and also registered it on my AAD and requested permission to access "webapiservice". The webapi client link is: http://webapiclient.azurewebsites.net
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://webapiservice.azurewebsites.net/");
//is this uri correct? should it be the link of webapi service or the one of webapi client?
HttpResponseMessage response = client.GetAsync("api/values").Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsAsync<IEnumerable<string>>().Result;
return result;
}
else
{
return new string[] { "Something wrong" };
}
So theoretically, I should receive the correct results from webapiservice. but I always received "Something wrong".
Am I missing anything here?
You need an access token from Azure AD.
There are plenty of good example apps on GitHub, here is one for a Daemon App: https://github.com/Azure-Samples/active-directory-dotnet-daemon/blob/master/TodoListDaemon/Program.cs#L96
AuthenticationResult authResult = await authContext.AcquireTokenAsync(todoListResourceId, clientCredential);
This app fetches an access token with its client id and client secret for an API. You can follow a similar approach in your case. You can just replace todoListResourceId with "https://graph.windows.net/" for Azure AD Graph API, or "https://graph.microsoft.com/" for Microsoft Graph API, for example. That is the identifier for the API that you want a token for.
This is the way it works in AAD. You want access to an API, you ask for that access from AAD. In a successful response you will get back an access token, that you must attach to the HTTP call as a header:
Authorization: Bearer accesstokengoeshere......
Now if you are building a web application, you may instead want to do it a bit differently, as you are now accessing the API as the client app, not the user. If you want to make a delegated call, then you will need to use e.g. the Authorization Code flow, where you show the user a browser, redirect them to the right address, and they get sent back to your app for login.
To call web api protected by azure ad , you should pass this obtained access token in the authorization header using a bearer scheme :
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);