---
"@context": https://schema.org
"@type": TechArticle
"@id": https://www.twilio.com/docs/usage/webhooks/webhook-auth-profiles#article
headline: Authenticate webhooks with OAuth 2.0, Basic, or Digest
description: Let Twilio authenticate itself to your webhook endpoints using OAuth 2.0 client credentials, HTTP Basic, or HTTP Digest.
url: https://www.twilio.com/docs/usage/webhooks/webhook-auth-profiles
inLanguage: en
dateModified: 2026-09-07T13:32:03.000Z
author:
  "@type": Organization
  name: Twilio Developer Education Team
publisher:
  "@type": Organization
  name: Twilio
---

# Authenticate webhooks with OAuth 2.0, Basic, or Digest

> \[!IMPORTANT]
>
> 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][sla] covers Public Beta products.

[sla]: https://help.twilio.com/articles/115002413087-Twilio-Beta-product-support

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.

> \[!WARNING]
>
> 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][59202]. Scope Basic authentication to an exact-match or prefix-match [Rule][rules], or use OAuth 2.0 or HTTP Digest on the default Rule.

Authentication and [signing][keys] 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.

## Use inline credentials or an AuthProfile

Twilio stores credentials in a required [Webhook Setting][settings] `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`.

## OAuth 2.0

## HTTP Basic

## HTTP Digest

## No Auth

## OAuth 2.0

To fetch an access token from your authorization server, Twilio uses the [client credentials flow][ccflow]. Twilio then sends the token as a [`Bearer` token][bearer] in the `Authorization` header of each webhook. When a token nears expiry, Twilio requests a replacement.

### Prerequisites

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

### Request body parameters \[#outh2-body-param]

| 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`.                   |

### Create an OAuth 2.0 AuthProfile

Make a `POST` request to the `AuthProfiles` resource.

```bash
curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \
     -H 'Content-Type: application/json' \
     -u {API_KEY_SID}:{API_KEY_SECRET} \
     -d '{
           "type": "OAUTH2",
           "friendlyName": "Example authorization server",
           "tokenUrl": "https://auth.example.com/oauth2/token",
           "clientId": "{CLIENT_ID}",
           "clientSecret": "{CLIENT_SECRET}",
           "scope": "webhooks:write",
           "clientCredentialsAuthMethod": "CLIENT_SECRET_POST"
         }'
```

Returns `201 Created`.

Save the returned `id`. Reference it from a Setting's `auth` object, then apply that Setting with a [Webhook Rule][rules].

### What Twilio sends to your authorization server

With `CLIENT_SECRET_POST`, Twilio puts the credentials in the form body.

```bash
curl -X POST https://auth.example.com/oauth2/token \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=client_credentials" \
     -d "client_id={CLIENT_ID}" \
     -d "client_secret={CLIENT_SECRET}"
```

If you set a scope or an audience, Twilio includes them.

```bash
curl -X POST https://auth.example.com/oauth2/token \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=client_credentials" \
     -d "client_id={CLIENT_ID}" \
     -d "client_secret={CLIENT_SECRET}" \
     -d "scope=webhooks:write" \
     -d "audience=https://api.example.com"
```

With `CLIENT_SECRET_BASIC`, Twilio sends the client ID and secret in an `Authorization: Basic` header instead of the body.

### What your authorization server must return

A JSON body containing at least `access_token`, `token_type`, and `expires_in`. The token type must be `Bearer`.

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

### When token retrieval fails

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][97001] in the [Twilio Debugger][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`.

## HTTP Basic

### Request body parameters \[#basic-body-param]

| Field              | Necessity | Description                               |
| ------------------ | --------- | ----------------------------------------- |
| `scheme` or `type` | required  | `BASIC`.                                  |
| `username`         | required  | The username Twilio sends.                |
| `password`         | required  | The password. Write-only, never returned. |

```bash
curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \
     -H 'Content-Type: application/json' \
     -u {API_KEY_SID}:{API_KEY_SECRET} \
     -d '{
           "type": "BASIC",
           "friendlyName": "Partner endpoint",
           "username": "{USERNAME}",
           "password": "{PASSWORD}"
         }'
```

## HTTP Digest

To use HTTP Digest, include the same `username` and `password` fields as Basic but set `"type": "DIGEST"`.

```bash
curl -X POST https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \
     -H 'Content-Type: application/json' \
     -u {API_KEY_SID}:{API_KEY_SECRET} \
     -d '{
           "type": "DIGEST",
           "friendlyName": "Legacy endpoint",
           "username": "{USERNAME}",
           "password": "{PASSWORD}"
         }'
```

## No authentication

Every setting requires the `auth` parameter. When Twilio shouldn't authenticate itself, set the `scheme` to `NONE`.

```json
{ "auth": { "source": "INLINE", "value": { "scheme": "NONE" } } }
```

## Manage AuthProfiles

### List all AuthProfiles

Never include Secrets.

```bash
curl -X GET https://webhooks.twilio.com/v1/Webhooks/AuthProfiles \
     -u {API_KEY_SID}:{API_KEY_SECRET}
```

### Fetch one AuthProfile

```bash
curl -X GET https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \
     -u {API_KEY_SID}:{API_KEY_SECRET}
```

### Update an AuthProfile

Only `friendlyName` is editable.

```bash
curl -X PATCH https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \
     -H 'Content-Type: application/json' \
     -u {API_KEY_SID}:{API_KEY_SECRET} \
     -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`.

### Delete one AuthProfile

To delete one AuthProfile, make a `DELETE` request of the `AuthProfiles` resource with its ID.

```bash
curl -X DELETE https://webhooks.twilio.com/v1/Webhooks/AuthProfiles/{AUTH_PROFILE_ID} \
     -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.

```bash
curl -X GET 'https://webhooks.twilio.com/v1/Webhooks/Settings?authProfileId={AUTH_PROFILE_ID}' \
     -u {API_KEY_SID}:{API_KEY_SECRET}
```

## Rotate credentials with no downtime

You can't change anything in an AuthProfile except its `friendlyName`. To rotate credentials, replace the resource.

1. Create a AuthProfile with the updated credentials.
2. Create a [Setting][settings] that references the AuthProfile.
3. [Test][testing] the added Setting against your endpoint.
4. Shift your [Rule][rules-traffic] onto the added Setting. If you want to validate on live traffic first, make the shift gradually.
5. Delete the old Setting.
6. Delete the old AuthProfile.

## Frequently asked questions

### Does authentication replace signature validation?

No. A signature proves the request wasn't tampered with. Keep [validating signatures][webhook-security], and always validate them if you serve webhooks over HTTP rather than HTTPS.

### Can I use both authentication and signing?

Yes. `auth` and `signature` are independent fields on the same Setting. Twilio encourages configuring at least one, over HTTPS.

### Can I use an OAuth 1 authorization server?

No. OAuth 1 isn't compatible with OAuth 2.0.

### Do I need to allowlist any IP addresses?

Accounts with [Twilio Editions][editions] reach your authorization server through static proxy addresses.

### Why does creating an AuthProfile fail with an authentication error?

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][sends].

## What's next?

* [Sign webhooks with shared keys][keys], to sign requests as well as authenticate them
* [Configure webhook settings][settings], to reference these credentials from a Setting
* [Test webhook delivery][testing], to check the credentials against your endpoint
* [Configure webhook rules][rules], to apply that Setting to your webhooks
* [Configuration API FAQs][faq]

[59202]: /docs/api/errors/59202

[97001]: /docs/api/errors/97001

[bearer]: https://datatracker.ietf.org/doc/html/rfc6750#section-2.1

[ccflow]: https://datatracker.ietf.org/doc/html/rfc6749#section-4.4

[debugger]: /docs/usage/troubleshooting/debugging-your-application

[editions]: https://www.twilio.com/en-us/editions

[keys]: /docs/usage/webhooks/webhook-shared-keys

[rules]: /docs/usage/webhooks/webhook-rules

[rules-traffic]: /docs/usage/webhooks/webhook-rules#shift-traffic-between-settings

[sends]: #what-twilio-sends-to-your-authorization-server

[settings]: /docs/usage/webhooks/webhook-settings

[testing]: /docs/usage/webhooks/webhook-testing

[webhook-security]: /docs/usage/webhooks/webhooks-security

[faq]: /docs/usage/webhooks/webhook-configuration-faq
