2
votes

The docs for the OAuth2 auth code to token exchange show making a request using client_id and client_secret. However is there a way to do this using cert based auth for the azure app?

1

1 Answers

4
votes

Yes you can acquire tokens using a certificate instead of using client secret as well. It's covered as part of Client Credentials Grant.

Azure AD V1 Endpoint

Here is a detailed code sample - It makes use of a self signed certificate and uses Azure AD V1 endpoint

Authenticating to Azure AD in daemon apps with certificates

certCred = new ClientAssertionCertificate(clientId, cert);
result = await authContext.AcquireTokenAsync(todoListResourceId, certCred);

In case you're looking to make direct REST based calls (not using ADAL Library) here's a sample. You can read more details on each of the parameters here on Microsoft Docs:

Access token request with a certificate

POST /<tenant_id>/oauth2/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

resource=https%3A%2F%contoso.onmicrosoft.com%2Ffc7664b4-cdd6-43e1-9365-c2e1c4e1b3bf&client_id=97e0a5b7-d745-40b6-94fe-5f77d35c6e05&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg&grant_type=client_credentials

Azure AD V2 Endpoint

Using MSAL.NET Library you can do it like this. Both client secret and Certificate Credentials variations are shown here. (Certificate is covered in the else case)

More details available here - Client credential flows in MSAL.NET

// Even if this is a console application here, a daemon application is a confidential client application
IConfidentialClientApplication app;

#if !VariationWithCertificateCredentials
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
           .WithTenantId("{tenantID}")
           .WithClientSecret(config.ClientSecret)
           .Build();
#else
// Building the client credentials from a certificate
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
    .WithTenantId("{tenantID}")
    .WithCertificate(certificate)
    .Build();
#endif

// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
// a tenant administrator
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };

AuthenticationResult result = null;
try
{
 result = await app.AcquireTokenForClient(scopes)
                   .ExecuteAsync();
}
catch(MsalServiceException ex)
{
 // Case when ex.Message contains:
 // AADSTS70011 Invalid scope. The scope has to be of the form "https://resourceUrl/.default"
 // Mitigation: change the scope to be as expected
}

Again in case you're interested in making direct REST based calss (not using MSAL Library) here's a sample.You can read more details on each of the parameters here on Microsoft Docs:

Access token request with a certificate

POST /{tenant}/oauth2/v2.0/token HTTP/1.1               // Line breaks for clarity
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_id=97e0a5b7-d745-40b6-94fe-5f77d35c6e05
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg
&grant_type=client_credentials