Authenticate webhooks with OAuth 2.0, Basic, or Digest
Public Beta
The Webhooks configuration API, including the Webhook Settings and Webhook Rules resources, has been released as a Public Beta product. Before Twilio declares this product as Generally Available, the information contained in this document might change. Twilio might implement additional features or change others. No Twilio SLA covers Public Beta products.
Your webhook endpoint can require Twilio to authenticate itself as any other API client would. Twilio supports OAuth 2.0 client credentials, HTTP Basic, and HTTP Digest.
Set the default rule to use anything but HTTP Basic authentication
A default Rule matches every otherwise-unmatched webhook URL. This results in sending Basic credentials to every destination that Twilio calls. Twilio rejects that with error 59202. Scope Basic authentication to an exact-match or prefix-match Rule, or use OAuth 2.0 or HTTP Digest on the default Rule.
Authentication and signing solve different problems and work independently. Authentication proves Twilio can call your endpoint. A signature proves the integrity of request body in transit. Use authentication, signatures, of both over secure HTTP.
Twilio stores credentials in a required Webhook Setting auth object in one of two forms.
| Form | When to use it |
|---|---|
Inline (source: INLINE) | Each Setting has its own credentials. Recommended for most accounts. |
AuthProfile (source: REFERENCE) | Several Settings share one set of credentials, so you rotate them in one place. |
The standalone resource AuthProfile stores one set of credentials. To access these settings, get the authProfileId.
To fetch an access token from your authorization server, Twilio uses the client credentials flow. Twilio then sends the token as a Bearer token in the Authorization header of each webhook. When a token nears expiry, Twilio requests a replacement.
An OAuth 2.0 authorization server with client credentials support, and from it:
- The token endpoint URL
- A client ID
- A client secret
- Optionally, a scope
- Optionally, an audience
| Field | Necessity | Description |
|---|---|---|
scheme or type | required | OAUTH2. Use scheme for inline credentials, type for an AuthProfile. |
tokenUrl | required | Your authorization server's token endpoint. |
clientId | required | The OAuth 2.0 client identifier. |
clientSecret | required | The OAuth 2.0 client secret. Write-only, and never returned in a response. |
scope | optional | The scope Twilio requests. |
audience | optional | The audience Twilio requests. |
clientCredentialsAuthMethod | optional | CLIENT_SECRET_POST (default) or CLIENT_SECRET_BASIC. |
Make a POST request to the AuthProfiles resource.
1curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \2-H 'Content-Type: application/json' \3-u {API_KEY_SID}:{API_KEY_SECRET} \4-d '{5"type": "OAUTH2",6"friendlyName": "Example authorization server",7"tokenUrl": "https://auth.example.com/oauth2/token",8"clientId": "{CLIENT_ID}",9"clientSecret": "{CLIENT_SECRET}",10"scope": "webhooks:write",11"clientCredentialsAuthMethod": "CLIENT_SECRET_POST"12}'
Returns 201 Created.
Save the returned id. Reference it from a Setting's auth object, then apply that Setting with a Webhook Rule.
If Twilio can't exchange your credentials for a token, it retries twice, 250 milliseconds apart. If those also fail, Twilio drops the webhook and logs error 97001 in the Twilio Debugger. Twilio tries again after 300 seconds, and webhooks matching that Setting may be dropped during that window.
Common causes are an unreachable authorization server, rotated or removed credentials, and a token issued with a type other than Bearer.
| Field | Necessity | Description |
|---|---|---|
scheme or type | required | BASIC. |
username | required | The username Twilio sends. |
password | required | The password. Write-only, never returned. |
1curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \2-H 'Content-Type: application/json' \3-u {API_KEY_SID}:{API_KEY_SECRET} \4-d '{5"type": "BASIC",6"friendlyName": "Partner endpoint",7"username": "{USERNAME}",8"password": "{PASSWORD}"9}'
To use HTTP Digest, include the same username and password fields as Basic but set "type": "DIGEST".
1curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \2-H 'Content-Type: application/json' \3-u {API_KEY_SID}:{API_KEY_SECRET} \4-d '{5"type": "DIGEST",6"friendlyName": "Legacy endpoint",7"username": "{USERNAME}",8"password": "{PASSWORD}"9}'
Every setting requires the auth parameter. When Twilio shouldn't authenticate itself, set the scheme to NONE.
{ "auth": { "source": "INLINE", "value": { "scheme": "NONE" } } }
Never include Secrets.
1curl -X GET https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \2-u {API_KEY_SID}:{API_KEY_SECRET}
1curl -X GET https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \2-u {API_KEY_SID}:{API_KEY_SECRET}
Only friendlyName is editable.
1curl -X PATCH https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \2-H 'Content-Type: application/json' \3-u {API_KEY_SID}:{API_KEY_SECRET} \4-d '{ "friendlyName": "Example authorization server (EU)" }'
To change tokenUrl, clientId, clientSecret, or any other credential field, create a different AuthProfile and point your Settings to the created AuthProfile.
To delete one AuthProfile, make a DELETE request of the AuthProfiles resource with its ID.
1curl -X DELETE https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \2-u {API_KEY_SID}:{API_KEY_SECRET}
A successful request returns 204 No Content. A failed request returns 409 Conflict as a Setting still references it. To resolve the error, find the dependent Settings, then change where they point or delete them.
1curl -X GET 'https://webhooks.twilio.com/v1/Webhooks/Settings?authProfileId={AUTH_PROFILE_ID}' \2-u {API_KEY_SID}:{API_KEY_SECRET}
You can't change anything in an AuthProfile except its friendlyName. To rotate credentials, replace the resource.
- Create a AuthProfile with the updated credentials.
- Create a Setting that references the AuthProfile.
- Test the added Setting against your endpoint.
- Shift your Rule onto the added Setting. If you want to validate on live traffic first, make the shift gradually.
- Delete the old Setting.
- Delete the old AuthProfile.
No. A signature proves the request wasn't tampered with. Keep validating signatures, and always validate them if you serve webhooks over HTTP rather than HTTPS.
Yes. auth and signature are independent fields on the same Setting. Twilio encourages configuring at least one, over HTTPS.
Accounts with Twilio Editions reach your authorization server through static proxy addresses.
Twilio validates OAuth 2.0 credentials when you create the resource by fetching a token. A 400 means that fetch failed. Check your authorization server's logs, then reproduce the token request with the curl commands under What Twilio sends to your authorization server.
- Sign webhooks with shared keys, to sign requests as well as authenticate them
- Configure webhook settings, to reference these credentials from a Setting
- Test webhook delivery, to check the credentials against your endpoint
- Configure webhook rules, to apply that Setting to your webhooks
- Configuration API FAQs