Skip to content

Instantly share code, notes, and snippets.

@schaabs
Last active September 22, 2021 11:57
Show Gist options
  • Save schaabs/edbce217621e5ce5aca1a8fa6f711952 to your computer and use it in GitHub Desktop.
Save schaabs/edbce217621e5ce5aca1a8fa6f711952 to your computer and use it in GitHub Desktop.
Defining Custom Credential Types

Authenticating with a prefetched access token

The Azure.Identity library does not contain a TokenCredential implementation which can be constructed directly with an AccessToken. This is intentionally omitted as authenticating a client with a static token is in most cases an anti-pattern, as access tokens expire frequently and have constrained usage. However, there are some scenarios where authenticating a service client with a prefetched token is necessary.

In this example StaticTokenCredential implements the TokenCredential abstraction. It takes a prefetched access token in its constructor as a string or AccessToken, and simply returns that from its implementation of GetToken and GetTokenAsync.

public class StaticTokenCredential : TokenCredential
{
    private AccessToken _token;

    public StaticTokenCredential(string token) : this(new AccessToken(token, DateTimeOffset.MinValue)) { }

    public StaticTokenCredential(AccessToken token)
    {
        _token = token;
    }

    public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return _token;
    }

    public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return new ValueTask<AccessToken>(_token);
    }
}

Once the application has defined this credential type instances of it can be used to authenticate Azure SDK clients. The following example shows an how an application already using some other mechanism for acquiring tokens (in this case the hypothetical method AquireTokenForScope) could use the StaticTokenCredential to authenticate a BlobClient.

string token = AcquireTokenForScope("https://storage.azure.com/.default");

var credential = new StaticTokenCredential(token);

var client = new BlobClient(new Uri("https://aka.ms/bloburl"), credential);

It should be noted when using this custom credential type, it is the responsibility of the caller to ensure that the token is valid, and contains the correct claims needed to authenticate calls from the particular service client. For instance in the above case the token must have the scope "https://storage.azure.com/.default" to authorize calls to Azure Blob Storage.

Authenticating with the On Behalf Of Flow

Currently the Azure.Identity library doesn't provide a credential type for clients which need to authenticate with via the On Behalf Of flow. While future support for this is planned, users requiring this immediately will have to implement their own TokenCredential class.

In this example the OnBehalfOfCredential accepts a client id, client secret, and a user's access token, and creates an instance of IConfidentialClientApplication from the Microsoft.Identity.Client library (MSAL) to obtain an obo tokens which can be used to authenticate client requests.

public class OnBehalfOfCredential : TokenCredential
{
    private readonly IConfidentialClientApplication _confidentialClient;
    private readonly UserAssertion _userAssertion;

    public OnBehalfOfCredential(string clientId, string clientSecret, string userAccessToken)
    {
        _confidentialClient = ConfidentialClientApplicationBuilder.Create(clientId).WithClientSecret(clientSecret).Build();

        _userAssertion = new UserAssertion(userAccessToken);
    }

    public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return GetTokenAsync(requestContext, cancellationToken).GetAwaiter().GetResult();
    }

    public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        AuthenticationResult result = await _confidentialClient.AcquireTokenOnBehalfOf(requestContext.Scopes, _userAssertion).ExecuteAsync();

        return new AccessToken(result.AccessToken, result.ExpiresOn);
    }
}

The following example shows an how the OnBehalfOfCredential could be used to authenticate a BlobClient.

var oboCredential = new OnBehalfOfCredential(clientId, clientSecret, userAccessToken);

var client = new BlobClient(new Uri("https://myaccount.blob.core.windows.net/mycontainer/myblob"), oboCredential);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment