Skip to content

Supporting Azure AD OAuth 2.0 Client Credentials Grant Flow #5223

Open
@gustavnyberg

Description

@gustavnyberg

Azure AD OAuth 2.0 Client Credentials Grant Flow (https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow)

Content & configuration

Swagger/OpenAPI definition: 2.0

Swashbuckle.AspNetCore 4.0.1

Swagger-UI configuration options:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(resourceName, new Info {Title = urn});
c.CustomSchemaIds(i => i.FullName);
c.AddSecurityDefinition
(
oAuth2SecurityDefinitionName,
new OAuth2Scheme
{
Type = oAuth2,
Flow = application,
TokenUrl = tokenUrl,
Scopes = new Dictionary<string, string> { { oAuth2SecurityDefinitionName, userImpersonation } }
}
);
c.AddSecurityRequirement(new Dictionary<string, IEnumerable> {{oAuth2SecurityDefinitionName, new[] {userImpersonation}}});
});

SwaggerUI({
c.OAuthClientId(clientId);
c.OAuthClientSecret(clientSecret);
c.OAuthRealm(uri);
c.OAuthAppName(resourceName);
c.OAuthScopeSeparator(value: " ");
c.SwaggerEndpoint($"/swagger/{resourceName}/swagger.json", resourceName);
})

Is your feature request related to a problem?

The Swagger UI OAuth2 Application Flow does not support the Azure AD OAuth 2.0 Client Credentials Grant Flow for the V1 endpoint.

This is due to two things:

  1. The client_id and client_secret needs to be sent in the request body, instead of a Basic Auth Header, which now is the case.

  2. Microsoft also has an other key/value that needs to be included in the request body, namely 'resource' which is either the AppId (Guid) or the Uri (e.g. https://the-azure-resource-display-name.azurewebsites.net") for the Azure Resource, which is likely also the OAuthRealm.

  3. I have not been able to test if you also get both Delegated Permissions (aka Scopes, e.g. user_impersonation) and the Application Permissions (aka Roles) in the Token, since I don't come that far, but it needs to be ensured as well.

Describe the solution you'd like

Either you implement a separate hard coded flow for this like the ones you already have:

swagger-ui/src/core/plugins/auth/actions.js

export const authorizeApplication = ( auth ) => ( { authActions } ) => {
let { schema, scopes, name, clientId, clientSecret } = auth
let headers = {
Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
}
let form = {
grant_type: "client_credentials",
scope: scopes.join(scopeSeparator)
}

Add something like this:

export const authorizeAzureActiveDirectoryApplication = ( auth ) => ( { authActions } ) => {
let { schema, scopes, name, clientId, clientSecret } = auth
let form = {
grant_type: "client_credentials",
client_id : "your-client-id"
client_secret : "your-client-secret"
resource : "appId/appUri"
scope: scopes.join(scopeSeparator)
}

Or a more generic solution would be to add configuration for this.

You have done something like this in the Swagger UI OAuth2 Password Flow, where you can choose whether to send credentials in the Header or the Body.

Preferably this could also be done directly in the StartUp configuration looking something like this:

SwaggerUI({
c.OAuthClientId(clientId);
c.OAuthClientSecret(clientSecret);
c.SendOAuthClientCredentialsIn(BasicAuthHeader/RequestBody)
c.OAuthRealm(uri);
c.OAuthAppName(resourceName);
c.OAuthScopeSeparator(value: " ");
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string> {});
c.OAuthAdditionalRequestBodyParams(new Dictionary<string, string> {{"resource", uri}});
c.SwaggerEndpoint($"/swagger/{resourceName}/swagger.json", resourceName);
})

Describe alternatives you've considered

Using the implicit flow, which works, but then requires that you configure your Azure Resource to allow the Implicit Flow, that you have a User and not just an Application, that the User has the same access, scopes and roles as the Client Application has as well as that and that user impersonation is allowed.

Additional context

Azure AD OAuth 2.0 Client Credentials Grant Flow (https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow) is the recommended way of doing service to service calls using client credentials (shared secret or certificate) in Azure according to Microsoft and it would be great to be able to use the same Auth process in Swagger that is used in the actual flow.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions