2
votes

I've setup an Azure Mobile App Service backend and there is a Xamarin app consuming it's services. It uses custom authentication in the Azure Mobile App Service for registering and authenticating the users of the app.

For local development/debugging application's OWIN startup class contains some code to setup the authentication options of the app service, as described in https://azure.microsoft.com/nl-nl/documentation/articles/app-service-mobile-dotnet-backend-how-to-use-server-sdk/#local-debug.

In Azure the Mobile App Service's authentication is enabled (Authentication / Authorization) setting the 'Action to take when request is not authenticated' option to 'Allow request (no action)' so the application handles the request authentication.

This all works as desired.

Now we would like to support a custom domain on our Mobile App Service and support the current ourmobileappservice.azurewebsites.net domain. We've configured the custom domain, configured it's SSL certificate and all works well. New tokens are issued with the custom domain as audience/issuer and it's also validated in this manor.

But when issuing a token with ourmobileappservice.azurewebsites.net as audience/issuer, it's rejected during token validation. It seems only our custom domain is allowed as valid audience.

For local development we're specifying the app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions { ... }), also setting the ValidAudiences property. So I wanted to use this setup for the Azure environment as well, so we can specify multiple valid audiences for token validation. Note: of course the AppServiceAuthenticationOptions is different than for local development, e.g. SigningKey comes from Azure's environment variables).

Unfortunately Azure doesn't seem to use this at all. It still keeps failing in the exact same way. As you can see only the custom domain is specified as valid audience:

Warning JWT validation failed: IDX10214: Audience validation failed. Audiences: 'https://ourmobileappservice.azurewebsites.net/'. Did not match: validationParameters.ValidAudience: 'https://ourcustom.domain.com/' or validationParameters.ValidAudiences: 'null'.

How can I configure the Azure Mobile App Service with custom authentication setup so it's valid audiences supports both the custom domain as the previous ourmobileappservice.azurewebsites.net?

Edit

The valid audiences are specified for Azure as follows:

public static void ConfigureMobileApp(IAppBuilder app)
{
    ...

    app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
    {
        SigningKey = Environment.GetEnvironmentVariable("WEBSITE_AUTH_SIGNING_KEY"),
        ValidAudiences = new[] { "https://ourcustom.domain.com/", "https://ourmobileappservice.azurewebsites.net/" },
        ValidIssuers = new[] { "https://ourcustom.domain.com/", "https://ourmobileappservice.azurewebsites.net/" },
        TokenHandler = config.GetAppServiceTokenHandler()
    });

    ...
}
2
are you adding 'ourcustom.domain.com' to 'ValidAudiences' ?Brent Schmaltz
Yes, specifying both the custom domain and ourmobileappservice.azurewebsites.net in the ValidAudiences. But the configured ValidAudiences doesn't seem to be honored.steurt
can you share the code you use to set 'ValidAudiences" ?Brent Schmaltz
See the Edit section of my post for the code.steurt
thanks, ill poke around for a bit and get back ...Brent Schmaltz

2 Answers

1
votes

You can sign the token with any URL which you like in your custom auth provider. Whatever you specify in the AppServiceLoginHandler.CreateToken() method will go into the JWT.

When it comes to validation of the token, if you're debugging locally the list of URLs specified in the middleware will be used to validate the audience and issuer. In production Azure will magically use your default Azure domain and custom domains.

The way I did it was to create a new web.config AppSetting which contains the valid signing URLs for all environments.

 <add key="ValidUrls" value="https://api.myproductiondomain.com/, https://myproductionapp.azurewebsites.net/, http://localhost:59475/" />

In the Startup.MobillApp.cs I'm populating the valid audiences and issuers from this list.

MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();

if (string.IsNullOrEmpty(settings.HostName))
{
    // This middleware is intended to be used locally for debugging. By default, HostName will
    // only have a value when running in an App Service application.

    var validUrls = ConfigurationManager.AppSettings["ValidUrls"].Split(',').Select(u => u.Trim()).ToList();

    app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
    {
        SigningKey = ConfigurationManager.AppSettings["SigningKey"],
        ValidAudiences = validUrls,
        ValidIssuers = validUrls,
        TokenHandler = config.GetAppServiceTokenHandler()
    });
}

Now in my login method before generating the token, I'm checking that the hostname of the current request is in the same AppSetting whitelist. If it's valid use the current hostname as the Audience and Issuer for my token.

Something like this;

    // Get current URL
    var signingUrl = $"{this.Request.RequestUri.Scheme}://{this.Request.RequestUri.Authority}/";

    // Get list from AppSetting
    var validUrls = ConfigurationManager.AppSettings["ValidUrls"].Split(',').Select(u => u.Trim()).ToList();

    // Ensure current url is in whitelist
    if (!validUrls.Contains(signingUrl))
    {
        return this.Request.CreateUnauthorizedResponse();
    }


    var claims = new Claim[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.Id),          
    };

    var signingKey = this.GetSigningKey();

    // Sign token with this
    var audience = signingUrl;
    var issuer = signingUrl; 


    // Set expirey
    var expiry = TimeSpan.FromHours(72);

    // Generate token
    JwtSecurityToken token = AppServiceLoginHandler.CreateToken(
        claims,
        signingKey,
        audience,
        issuer,
        expiry
        );
0
votes

We actually just made a set of updates which allow you to set audiences in the portal. If you return to the AAD settings under App Service Authentication / Authorization, you should see some new options under the "Advanced" tab. This includes an editable list of allowed token audiences.

If you add https://ourmobileappservice.azurewebsites.net to that list, you should be good to go.