Microsoft Azure Authentication using Flutter Web - flutter-web

I am new to Flutter and I am stuck at a point where I need to authenticate my web app using Microsoft authentication. I didn't find any document related to this neither flutter have package to do so. I guess I need to write code in native platform and connect it to flutter. Help !!

Found one Flutter Microsoft authentication package you can try with importing in your flutter code.
import the Flutter Microsoft Authentication package into your flutter application by adding it to the list of dependencies in your pubsec.yaml file.
dependencies:
flutter_microsoft_authentication: ^0.1.0
Reference: https://pub.dev/packages/flutter_microsoft_authentication

1 year later I faced the same problem and didn't find any clear and working solution despite my searches.
Here is what I did. It may help some people until a clean and easy package is released supporting Flutter web too.
The concept is simple. In order to not handle user authentication, I want the user to challenge his credentials against an Identity Provider (IP): Azure Active Directory, and let Azure redirect him to my application with a security token.
The client application redirects the user to Microsoft authentication web application and pass a “callback url” that Azure will use to redirect the user once he is authenticated. By redirecting to the client app, Azure passes also an Access Token giving eventually some information regarding roles or permissions the recipient of this token may need to know. We can keep the token somewhere. Let’s say in a global variable:
class Globals {
String azureAccessToken = "";
Globals._privateConstructor();
static final Globals _instance = Globals._privateConstructor();
static Globals get instance => _instance;
}
The application handles routes and display either the main app widget if the token is known or the authenticate widget if no token are yet known
import 'package:flutter/material.dart';
import 'package:flutterweb_azuread_authentication/helpers/globals.dart';
import 'authenticate.dart';
import 'main_app.dart';
class FlutterAuthenticationApp extends StatefulWidget {
const FlutterAuthenticationApp({super.key});
#override
State<FlutterAuthenticationApp> createState() => _FlutterAuthenticationAppState();
}
class _FlutterAuthenticationAppState extends State<FlutterAuthenticationApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
routes:
{
"/":(context)=>Globals.instance.azureAccessToken==""?const Authenticate():const MainApp(),
}
)
;
}
}
The MainApp will simply display a message giving the token
import 'package:flutter/material.dart';
import 'package:flutterweb_azuread_authentication/helpers/globals.dart';
class MainApp extends StatefulWidget {
const MainApp({super.key});
#override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
#override
Widget build(BuildContext context) {
return
SelectableText("Seems you're authenticated. Your token is ${Globals.instance.azureAccessToken}");
}
}
The Authenticate widget displays a login button. When the user clicks login, he should be redirected to the Microsoft login app and then redirected to the app.
import 'package:flutter/material.dart';
import 'package:openid_client/openid_client_browser.dart' as open_id;
class Authenticate extends StatefulWidget {
const Authenticate({super.key});
#override
State<Authenticate> createState() => _AuthenticateState();
}
class _AuthenticateState extends State<Authenticate> {
#override
Widget build(BuildContext context) {
var tenantId = "<your tenant id>";
var clientId = "<your app registration id>";
var scope = "api://<your scope>";
return Scaffold(
appBar: AppBar(title: const Text("Authenticate with Azure AD")),
body: Center(
child: ElevatedButton(
child: const Text("Login"),
onPressed: null,
),
),
);
}
}
When the user clicks on login, we need to redirect the application to Azure AD authentication, passing the relevant parameters including callback url. This call back url will have to get the token sent by Azure AD and finalize the flow.
Looking for existing package, I got into trouble with the following:
aad_oauth: for any reason, this package was not working for me. I was facing many dependencies issues and I think despite what is announced, this is not supporting Flutter Web.
flutter_aad_auth: not supporting web
azure_ad_authentication: not supporting web
Finally, I had to get my own solution using openid_client package, more precisely openid_client_browser.
This package handles the flow and especially redirect the Flutter Web app to Microsoft Azure authentication.
In order to use Azure AD, we obviously need an Active Directory configured. I will not describe it here. Be aware you'll need your tenandId, the Registration app ID and a scope. I try to explain a bit more in this article.
Now let’s use openid_client_browser to redirect to Azure AD authentication and observe what happens…
import 'package:flutter/material.dart';
import 'package:openid_client/openid_client_browser.dart' as open_id;
class Authenticate extends StatefulWidget {
const Authenticate({super.key});
#override
State<Authenticate> createState() => _AuthenticateState();
}
class _AuthenticateState extends State<Authenticate> {
#override
Widget build(BuildContext context) {
var tenantId = "<your tenant id>";
var clientId = "<your app registration id>";
var scope = "api://<your scope>";
return Scaffold(
appBar: AppBar(title: const Text("Authenticate with Azure AD")),
body: Center(
child: ElevatedButton(
child: const Text("Login"),
onPressed: () { authenticate(Uri.parse("https://login.microsoftonline.com/$tenantId/v2.0"), clientId, [scope]);
},
),
),
);
}
}
authenticate(Uri uri, String clientId, List<String> scopes) async {
var issuer = await open_id.Issuer.discover(uri);
var client = open_id.Client(issuer, clientId);
var authenticator = open_id.Authenticator(client, scopes: scopes);
await authenticator.credential;
authenticator.authorize();
}
When you click on the login button, the Microsoft login page displayed. Once you enter your credentials and finalize the login process, Azure redirects your browser to the root of your Flutter Web app adding #access_token=xxx
A bit strange to me that it is not using regular query parameters with ?access_token but we'll survive.
Now we have to extract the token from the URI as soon as we receive it.
So just before your main entry point run the App,
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutterweb_azuread_authentication/helpers/globals.dart';
import 'widget/flutter_authentication_app.dart';
void main() {
if (Uri.base.toString().contains("access_token=")) {
var idxStart = Uri.base.toString().indexOf("access_token=") + "access_token=".length;
var idxEnd = min(Uri.base.toString().length - 1, Uri.base.toString().indexOf("&token_type="));
var accessToken = Uri.base.toString().substring(idxStart, idxEnd);
Globals.instance.azureAccessToken = accessToken;
}
runApp(const FlutterAuthenticationApp());
}
It doesn't look super pretty due to the way I extract the token, but it does the job.
Sorry if this answer is a bit long but I wanted to be as clear as possible.
You can find the code on github

Related

How to configure Azure App Service (for Mobile) and B2C Authentication and access Azure SQL Database

I have a xamarin.forms mobile App using Microsoft.WindowsAzure.MobileServices and Microsoft.Identity.Client. Using EasyAuth I successfully got the xamarin mobile app to post data to the AzureSQL tables linked via connection string in the App Service configuration section. I use the local and offline sync methods of MobileServiceClient. I then attempted to change to B2C authentication. I setup a Tenant and under this tenant registered a new App as a native client called "MobileB2C". Redirect URIs were added automatically. I then created the signinsignup UserFlows.
Back to the Azure App Service (Mobile) under Authentication section I added a provider and selected the B2C App, MobileB2C. I did not populate the "allowed token audiences" field and Azure automatically created Client secret setting name "MICROSOFT_PROVIDER_AUTHENTICATION_SECRET" and the issuer URL.
So when I run the xamarin mobile app I can login via azure B2C and I can see that the authResult returns the users correct info along with UserIdentifier,aud, iss, sub, oid etc.
Once authResult is returned the xamarin mobile then tries to use the sync methods of MobileServiceClient to save data to the AzureSQL table. Its at this point that it fails. When the line await mClient.SyncContext.PushAsync().ConfigureAwait(false); is hit an error occurs described as Microsoft.WindowsAzure.MobileServices.Sync.MobileServicePushStatus.CancelledByAuthentication. I continued to try and confirgure the Azure back end differently and now I no linger get the CancelledByAuthentication error but instead get Microsoft.WindowsAzure.MobileServices.Sync.MobileServicePushStatus.CancelledByNetworkError.
The relevant xamarin mobile app code to implement the authentication and AzureSQL table update is as follows;
private B2CAuthenticationService()
{
// default redirectURI; each platform specific project will have to override it with its own
var builder = PublicClientApplicationBuilder.Create(B2CConstants.ClientID)
.WithB2CAuthority(B2CConstants.AuthoritySignInSignUp)
.WithIosKeychainSecurityGroup(B2CConstants.IOSKeyChainGroup)
.WithRedirectUri($"msal{B2CConstants.ClientID}://auth");
// Android implementation is based on https://github.com/jamesmontemagno/CurrentActivityPlugin
// iOS implementation would require to expose the current ViewControler - not currently implemented as it is not required
// UWP does not require this
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();
if (windowLocatorService != null)
{
builder = builder.WithParentActivityOrWindow(() => windowLocatorService?.GetCurrentParentWindow());
}
_pca = builder.Build();
}
public async Task<UserContext> SignInAsync()
{
UserContext newContext;
try
{
// acquire token silent
newContext = await AcquireTokenSilent();
}
catch (MsalUiRequiredException)
{
// acquire token interactive
newContext = await SignInInteractively();
}
return newContext;
}
private async Task<UserContext> SignInInteractively()
{
AuthenticationResult authResult = await _pca.AcquireTokenInteractive(B2CConstants.Scopes)
.ExecuteAsync();
var newContext = UpdateUserInfo(authResult);
UserSingleton.Instance.UserId = newContext.UserIdentifier;
return newContext;
}
THe xamarin mobile app adds a record to the local database and then RefreshItemsAsync begins the synchronisation to the AzureSQL.
await azureService.AddUserSurveyAsync(newSurvey).ConfigureAwait(false);
await azureService.RefreshItemsAsync(true).ConfigureAwait(false);
It is at the PushAsync line below that the the code fails.
public async Task InitializeAsync()
{
using (await initializationLock.LockAsync())
{
if (!isInitialized)
{
mClient = new MobileServiceClient(https://mobileservice.azurewebsites.net);
// Define the offline store.
mStore = new MobileServiceSQLiteStore("mobile3.db");
mStore.DefineTable<UserSurvey>();
await mClient.SyncContext.InitializeAsync(mStore, new MobileServiceSyncHandler()).ConfigureAwait(false);
UserSurveyTable = mClient.GetSyncTable<UserSurvey>();
isInitialized = true;
}
}
}
public async Task RefreshItemsAsync(bool syncItems)
{
if (syncItems)
{
await SynchronizeAsync().ConfigureAwait(false);
}
}
public async Task SynchronizeAsync()
{
await InitializeAsync().ConfigureAwait(false);
IReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
if (!CrossConnectivity.Current.IsConnected)
return;
try
{
await mClient.SyncContext.PushAsync().ConfigureAwait(false);
await UserSurveyTable.PullAsync("usersurveys", UserSurveyTable.CreateQuery()).ConfigureAwait(false);
}
catch (MobileServicePushFailedException error)
{
if (error.PushResult != null)
{
foreach (var result in error.PushResult.Errors)
{
await ResolveError(result);
}
}
}
}
What is wrong with the Azure back end configuration or perhaps I'm missing code as I can't understand how the xamarin mobile app can then attempt to communicate with the Azure Mobile App Service and AzureSQL as I don't send any token with those lines of code for PushAsync etc or perhaps this is abstracted away?
Here are images of the exceptions;
enter image description here
enter image description here
As promised, here is the succinct version of AAD authentication. For your purposes, B2C authentication is the same as AAD authentication.
There are two application definitions at play here - one for the mobile application (which basically says "this person is authenticated"), and one for the service (which says "a token authenticated for this mobile application can access this service"). So, you create an application ID for your mobile application, and an application ID for your service, and then you configure the service application ID to accept the mobile application.
The "WPF" tutorial for Azure Mobile Apps gives the general overview, although it's for WPF instead of Xamarin. The pieces you need are all the same.
The "WPF" tutorial here: https://learn.microsoft.com/en-us/azure/developer/mobile-apps/azure-mobile-apps/quickstarts/wpf/authentication

Authorization in Azure AD B2C for the react React Native app

Does anyone succeed in creating react native app with authorization in Azure Ad B2C?
I did it for the React web app and .Net Core API but, any library which I found for React Native does not work right know and I'm beginner in React Native. Please give me some hints tutorials or repos. I got stuck so bad.
I found an working React-Native library for Azure AD B2C. You can follow this article.
Here is the example:
import B2CAuthentication from "../auth-ad-js/ReactNativeADB2C";
import LoginView from "../auth-ad-js/LoginView";
const CLIENT_ID = "<provide your client id>";
export default class LoginScreen extends React.Component {
static navigationOptions = {
title: "Login"
};
render() {
const b2cLogin = new B2CAuthentication({
tenant: 'yourtenant.onmicrosoft.com',
client_id: CLIENT_ID,
client_secret: "<key set in application/key>",
user_flow_policy: "B2C_1_signupsignin",
reset_password_policy: 'B2C_1_password_reset',
token_uri: "https://saroujetmp.b2clogin.com/saroujetmp.onmicrosoft.com/oauth2/v2.0/token",
authority_host: "https://saroujetmp.b2clogin.com/saroujetmp.onmicrosoft.com/oauth2/v2.0/authorize",
redirect_uri: "https://functionapp120190131041619.azurewebsites.net/.auth/login/aad/callback",
prompt: "login",
scope: ["https://saroujetmp.onmicrosoft.com/api/offline_access", "offline_access"]
});
return (
<LoginView
context={b2cLogin}
onSuccess={this.onLoginSuccess.bind(this)}
/>
);
}
onLoginSuccess(credentials) {
console.log("onLoginSuccess");
console.log(credentials);
// use credentials.access_token..
}
}

Azure App Service with websockets and AD authentication

we got an application deployed as App Service and we are using SignalR for communication. After enabling AAD authentication - in browsers we started receiving 302 responses with redirect location to Azure AD.
Seems like the authentication layer on App Service is ignoring access_token passed by query string.
Request
Request URL: wss://<url>/hubs/chat?access_token=<token>
Request Method: GET
Response
Status Code: 302 Redirect
Location: https://login.windows.net/common/oauth2/authorize?...
After looking everywhere we couldn't find any solution to make this work.
The only solution to this issue that we see is either to disable authentication on App Service or use Long-Pooling, but both options are not acceptable in our situation.
By default, you web application will not get the access token from query string. Commonly, it will get the access token from authorization header or the cookie.
To get the access token from query string, you need to implement your custom authentication way.
Install Microsoft.Owin.Security.ActiveDirectory NuGet package.
Create an authentication provider which will get access token from query string.
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("access_token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(null);
}
}
Add map in .
app.Map("/yourpath", map =>
{
map.UseWindowsAzureActiveDirectoryBearerAuthentication(new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Provider = new QueryStringOAuthBearerProvider(),
Tenant = tenantId,
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = clientId
}
});
map.RunSignalR(hubConfiguration);
});
After multiple calls with Microsoft Technical Support, MS confirmed that App Service Authentication layer doesn't support access token passed in query string and there are no plans for this support yet. So there are two options:
Use different protocol for SignalR (long pooling works just fine)
Drop App Service Authentication
Using a custom middleware, I was able to update the request prior to authorization occurring:
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace Stackoverflow.Example.Security.Middleware
{
public class BearerTokenFromQueryToHeaderMiddleware
{
private readonly RequestDelegate _next;
public BearerTokenFromQueryToHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var token = context.Request.Query["access_token"];
if (!string.IsNullOrWhiteSpace(token))
{
context.Request.Headers.Add("Authorization", $"Bearer {token}");
}
await _next(context);
}
}
}
I didn't try to get this working with the OpenID framework, but I did test using a custom policy. As long as this is registered earlier than the authentication, then this middleware should execute prior to the framework looking for the token in the header.

Running asp.net core 2 app with OAuth2 as Azure Appservice results in 502 errors

I created a simple ASP.NET Core Web application using OAuth authentication from Google. I have this running on my local machine fine.
Yet after deploying this as an AppService to Azure the OAuth redirects seem to get messed up.
The app itself can be found here:
https://gcalworkshiftui20180322114905.azurewebsites.net/
Here's an url that actually returns a result and shows that the app is running:
https://gcalworkshiftui20180322114905.azurewebsites.net/Account/Login?ReturnUrl=%2F
Sometimes the app responds fine but once I try to login using Google it keeps loading forever and eventually comes back with the following message:
The specified CGI application encountered an error and the server terminated the process.
Behind the scenes, the authentication callback that seems to be failing with a 502.3 error:
502.3 Bad Gateway “The operation timed out”
The error trace can be found here:
https://gcalworkshiftui20180322114905.azurewebsites.net/errorlog.xml
The documentation from Microsoft hasn't really helped yet.
https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-overview
Further investigation leads me to believe that this has to do with the following code:
public GCalService(string clientId, string secret)
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json");
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = clientId,
ClientSecret = secret
},
new[] {CalendarService.Scope.Calendar},
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
// Create Google Calendar API service.
_service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "gcalworkshift"
});
}
As I can imagine Azure not supporting personal folders? Googling about this doesn't tell me much.
I followed Facebook, Google, and external provider authentication in ASP.NET Core and Google external login setup in ASP.NET Core to create a ASP.NET Core Web Application with Google authentication to check this issue.
I also followed .NET console application to access the Google Calendar API and Calendar.ASP.NET.MVC5 to build my sample project. Here is the core code, you could refer to them:
Startup.cs
public class Startup
{
public readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder); //C:\Users\{username}\AppData\Roaming\Google.Apis.Auth
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication().AddGoogle(googleOptions =>
{
googleOptions.ClientId = "{ClientId}";
googleOptions.ClientSecret = "{ClientSecret}";
googleOptions.Scope.Add(CalendarService.Scope.CalendarReadonly); //"https://www.googleapis.com/auth/calendar.readonly"
googleOptions.AccessType = "offline"; //request a refresh_token
googleOptions.Events = new OAuthEvents()
{
OnCreatingTicket = async (context) =>
{
var userEmail = context.Identity.FindFirst(ClaimTypes.Email).Value;
var tokenResponse = new TokenResponse()
{
AccessToken = context.AccessToken,
RefreshToken = context.RefreshToken,
ExpiresInSeconds = (long)context.ExpiresIn.Value.TotalSeconds,
IssuedUtc = DateTime.UtcNow
};
await dataStore.StoreAsync(userEmail, tokenResponse);
}
};
});
services.AddMvc();
}
}
}
CalendarController.cs
[Authorize]
public class CalendarController : Controller
{
private readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder);
private async Task<UserCredential> GetCredentialForApiAsync()
{
var initializer = new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "{ClientId}",
ClientSecret = "{ClientSecret}",
},
Scopes = new[] {
"openid",
"email",
CalendarService.Scope.CalendarReadonly
}
};
var flow = new GoogleAuthorizationCodeFlow(initializer);
string userEmail = ((ClaimsIdentity)HttpContext.User.Identity).FindFirst(ClaimTypes.Name).Value;
var token = await dataStore.GetAsync<TokenResponse>(userEmail);
return new UserCredential(flow, userEmail, token);
}
// GET: /Calendar/ListCalendars
public async Task<ActionResult> ListCalendars()
{
const int MaxEventsPerCalendar = 20;
const int MaxEventsOverall = 50;
var credential = await GetCredentialForApiAsync();
var initializer = new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "ASP.NET Core Google Calendar Sample",
};
var service = new CalendarService(initializer);
// Fetch the list of calendars.
var calendars = await service.CalendarList.List().ExecuteAsync();
return Json(calendars.Items);
}
}
Before deploying to Azure web app, I changed the folder parameter for constructing the FileDataStore to D:\home, but got the following error:
UnauthorizedAccessException: Access to the path 'D:\home\Google.Apis.Auth.OAuth2.Responses.TokenResponse-{user-identifier}' is denied.
Then, I tried to set the parameter folder to D:\home\site and redeploy my web application and found it could work as expected and the logged user crendentials would be saved under the D:\home\site of your azure web app server.
Azure Web Apps run in a secure environment called the sandbox which has some limitations, details you could follow Azure Web App sandbox.
Additionally, you mentioned about the App Service Authentication which provides build-in authentication without adding any code in your code. Since you have wrote the code in your web application for authentication, you do not need to set up the App Service Authentication.
For using App Service Authentication, you could follow here for configuration, then your NetCore backend can obtain additional user details (access_token,refresh_token,etc.) through an HTTP GET on the /.auth/me endpoint, details you could follow this similar issue. After retrieved the token response for the logged user, you could manually construct the UserCredential, then build the CalendarService.

Getting Unauthorized from from Azure Web API

I created a basic project using Visual Studio 2015 Update 3 for Web API (nothing custom, bare bone) and deployed it to Azure (Free Account) following the instruction here.
Then I created a Console client with the following code.
public static async Task<bool> ReadValues()
{
try
{
// Authenticate the user and get a token from Azure AD
//AuthenticationResult authResult = await AuthContext.AcquireTokenSilentAsync(Resource, ClientId);
AuthenticationResult authResult = AuthContext.AcquireToken(Resource, ClientId, RedirectUri);
// Create an HTTP client and add the token to the Authorization header
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
//"Bearer"
authResult.AccessTokenType
, authResult.AccessToken);
// Call the Web API to get the values
var requestUri = new Uri(WebApiUri, "api/values");
Console.WriteLine("Reading values from '{0}'.", requestUri);
HttpResponseMessage httpResponse = await httpClient.GetAsync(requestUri);
Console.WriteLine("HTTP Status Code: '{0}'", httpResponse.StatusCode.ToString());
//Console.WriteLine("HTTP Header: '{0}'", httpClient.DefaultRequestHeaders.Authorization.ToString());
if (httpResponse.IsSuccessStatusCode)
{
//
// Code to do something with the data returned goes here.
//
var s = await httpResponse.Content.ReadAsStringAsync();
Console.WriteLine(s);
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(httpResponse.ReasonPhrase);
}
return (httpResponse.IsSuccessStatusCode);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return false;
}
It works fine when I run the WEB API locally from the Visual Studio in debug, but when I deploy it to the Azure, it returns Unauthorized.
Few common things that I might get asked:
I do receive a valid bearer token
I have created the App registrations in the Azure AD for bot hthe WEB API and the client
The client and WEB API are using the correct redirect, resource uri
The account I am using to login is the same as the one used to create the Azure account and it has full privileges in the domain/AD/API
On the API side, this is whole of the startup.auth.cs
using System.Configuration;
using System.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Security.ActiveDirectory;
using Owin;
using WebApi;
[assembly: OwinStartup("default", typeof(Startup))]
namespace WebApi
{
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
}
}
}
What else should I check?
Other references
https://www.simple-talk.com/cloud/security-and-compliance/azure-active-directory-part-3-developing-native-client-applications/
Thanks for help from Juunas who provided me with a working copy, I was able to narrow down the cause. When I attached a debugger to the Azure instance of the Web API I was able to see a exception for Bad Audience. On trying to retrace my steps, I found that while deployment from Visual Studio, I was selection Enterprise Authentication in settings that was causing the web.config to change in way that lead to the problem. Not selecting that option, I was able to access the API through bearer token.

Resources