Search code examples
apiazureazure-active-directoryazure-api-apps

Accessing authenticated Azure API APP


I have an Azure API APP that I have set up to use Azure AD authentication. Like so:

enter image description here

I also have a console app that have a generated client API to my API APP like this:

enter image description here

If I disable the authentication on the API APP, I can call the API from my console app. If I enable the Azure AD authentication, the client can not call the API due to "not authorized" exception, which is ofcourse expected.

I have searched all over the place to find any information on how to supply credentials of the correct type to the API. There is a client.Credentials property that can be either TokenCredentials or BasicAuthenticationCredentials

What would be the correct way to authenticate the client through the Azure AD if I have username and password for the AD user?

I am unable to find any documentation that relates to the auto generated API clients from the Azure SDK.

[Edit] The reply from @chrisgillum leads to an article on how to do this:

internal class Program
{
    [STAThread]
    private static void Main(string[] args)
    {
        var uri = new Uri("https://ro....azureapp.azurewebsites.net");
        var client = new LearningAzure(uri);
        client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
            ServicePrincipal.GetS2SAccessTokenForProdMSA().AccessToken);
        var res = client.Foo.GetById(123);
    }
}


public static class ServicePrincipal
{
    // The _authority is the issuer URL of the tenant.
    private static readonly string _authority = "https://login.windows.net/ro....ouse.onmicrosoft.com";

    // The _resource is the Client ID of the "data web api" AAD app.
    private static readonly string _resource = "b8b0.....8e3623d";

    // The Client ID of the "client" AAD app (i.e. this app).
    private static readonly string _clientId = "d25892.....33a0";

    // The key that was created for the "client" app (i.e. this app).
    private static readonly string _clientSecret = "??????";

    public static AuthenticationResult GetS2SAccessTokenForProdMSA()
    {
        return GetS2SAccessToken(_authority, _resource, _clientId, _clientSecret);
    }


    /// <summary>
    ///     Gets an application token used for service-to-service (S2S) API calls.
    /// </summary>
    private static AuthenticationResult GetS2SAccessToken(string authority, string resource, string clientId,
        string clientSecret)
    {
        // Client credential consists of the "client" AAD web application's Client ID
        // and the key that was generated for the application in the AAD Azure portal extension.
        var clientCredential = new ClientCredential(clientId, clientSecret);

        // The authentication context represents the AAD directory.
        var context = new AuthenticationContext(authority, false);

        // Fetch an access token from AAD.
        var authenticationResult = context.AcquireToken(
            resource,
            clientCredential);
        return authenticationResult;
    }
}

The _clientSecret how do I get this one? The client app configured in my Azure AD does not have any options to generate a secret.

Published web apps can, but my custom created native app only has a client Id on the configure page. Ideas?


Solution

  • To get credentials on a console app, if you are prompting for a user login, you can use their credentials to acquire a token. Otherwise, you need to use a Client App Key (which is a client App URI and matching API key) to acquire a token.

    Uri aadUri = new Uri(_settings.AadUri);
    Uri authorityUri = new Uri(aadUri, _settings.TenantUri);
    string authority = authorityUri.ToString();
    
    AuthenticationResult authorizationResult;
    var authenticationContext = new AuthenticationContext(authority, new TokenCache());
    
    var clientCredential = new ClientCredential(_settings.ClientId, _settings.AppKey);
    authorizationResult = authenticationContext.AcquireToken(_settings.AppIdUri, clientCredential);
    

    You also need to make sure your app URI is in the manifest for the service endpoint (or somehow provisions to give your app in azure access to the Azure AD).