简体   繁体   中英

Sendgrid Webhook to authenticate using Azure (AAD, MSAL) machine-to-machine

Context

I have an application that acts as Sendgrid Webhook handler. To implement OAuth 2, I currently have an in-app authorization server based on OpenIddict . It works.

The application exchanges a local scope JWT using a local authorization endpoint, which is backed by an in-memory EF DbContext storing client ID and credential, where the credential ultimately comes from the Azure Environment (setting an env variable in the PaaS instance). As I said, it works.

The drawback is that the Sendgrid credentials (client ID and secret) are stored inside the application and I am still exchanging a local JWT with the drawback of key management. Motivating: the application currently uses an ephemeral JWK, so it can't scale horizontally until I store the key in a Key Vault or such. The problem is also by design because all our company uses MS Azure as platform, so leveraging Azure tools such as MS AAD is better than implementing our own authentication provider, despite the great work done by the open source community.

I already have an app registration on our B2C tenant, where front-end users can authenticate using OIDC (endpoint https://login.microsoftonline.com/<our-tenant-id>/v2.0/.well-known/openid-configuration ). Users can log in to the application.

Question

How can I use a Microsoft-Azure-based identity to authenticate Sendgrid Webhook in machine-to-machine mode? I want the Sendgrid credentials to be stored in the cloud, not in our application (which is deployed to Azure... but you know what I mean.), Sendgrid should be configured to exchange a JWT from Microsoft Azure. and give it to our application. I want to remove the Authorization Server part from the app.

Sendgrid takes the following:

  • Authorization method: must be OAuth 2
  • Client ID
  • Client Secret
  • Token URL
  • HTTP POST URL, which is my application's endpoint

What I tried so far: creating an Azure AD B2C user/password for Sendgrid

Using Azure AD B2C portal, I entered our directory and created a new user sendgridhook@<our-tenant>.onmicrosoft.com with a password to enter into Sendgrid. I had configured ngrok in order to divert traffic to my local host instance, and gave it a try. Did not receive test events.

The problem was likely the authentication. I tried to run the following

❯ Invoke-WebRequest -Method Post -Uri https://login.microsoftonline.com/<tenant-guid>/oauth2/v2.0/token -ContentType "application/x-www-form-urlencoded" 
-Body "client_id=sendgridhook@<tenant>.onmicrosoft.com&client_secret=<password>&grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default"
Invoke-WebRequest: {"error":"unauthorized_client","error_description":"AADSTS700016: Application with identifier 'sendgridhook' was not found in the directory '<tenant-guid>'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.......",
"error_codes":[700016],"timestamp":"...","trace_id":"....","correlation_id":"...","error_uri":"https://login.microsoftonline.com/error?code=700016"}

AADSTS700016: Application with identifier 'sendgridhook' was not found in the directory ''. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.......

Conclusion : probably the user must authenticate interactively, not as a machine-user

Second attempt: use App Registration's client credentials

I already use an App Registration for the implicit flow in Angular, so I tried to create a secret credential for it. Result is interesting.

❯ (Invoke-WebRequest -Method Post -Uri https://login.microsoftonline.com/<tenant-guid>/oauth2/v2.0/token -ContentType "application/x-www-form-urlencoded" -Body "client_id=<app-registration-client-id>&client_secret=<newly-generate-credential>&grant_type=client_credentials&scope=https://<tenant>.onmicrosoft.com/<app-name>/.default").Content
{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyIsImtpZCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyJ9......."}

So I obtained a JWT. Now, the problem is that Sendgrid can't be configured because of the scope. The scope here was added by me , and I can't even try to barely change the url to /token?scope=[...] to hope Microsoft takes the scope from the URL.

As I said above, Sendgrid only takes client ID, client secret and token endpoint. It takes no scope.

I also ran into this and after some digging I couldn't find anyone who posted an answer to this. I have however found that if you use the v1 token endpoint it will work without specifying scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM