> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daily.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-signing meeting tokens

> Generate Daily meeting tokens locally using your API key, without making a round-trip to the Daily API.

<Warning>
  If you're unfamiliar with JWTs and how to create them, use the [`/meeting-tokens` endpoint](/reference/rest-api/meeting-tokens/create-meeting-token) instead.
</Warning>

Using your [API key](https://dashboard.daily.co/developers), you can self-sign tokens that will be accepted by the Daily backend, as long as the API key is still active at the time it is checked. This saves making a round-trip to the Daily API to generate tokens, which is useful if you need to update tokens often or create them in bulk.

## Generating self-signed tokens

Create a JWT using your domain's API key as the secret. The payload must include:

* **`r`**: the room name
* **`iat`**: the current time (Unix timestamp)
* **`d`**: your `domain_id`

```json theme={null}
{ "r": "test", "iat": 1610596413, "d": "30f866c3-9123-452a-8723-ff58322d09c5" }
```

Your `domain_id` is available from the [domain configuration endpoint](/reference/rest-api/domain/get-domain-config#response-domain-id).

To learn more about and test your tokens, refer to [https://jwt.io/](https://jwt.io/).

## Token property abbreviations

Self-signed token [properties](/reference/rest-api/meeting-tokens/create-meeting-token#body-properties) use shortened field names in the JWT payload:

| Property | Abbreviation |
| - | - |
| `nbf` | `nbf` |
| `exp` | `exp` |
| `domain_id` | `d` |
| `room_name` | `r` |
| `user_id` | `ud` |
| `user_name` | `u` |
| `is_owner` | `o` |
| `knocking` | `k` |
| `close_tab_on_exit` | `ctoe` |
| `redirect_on_meeting_exit` | `rome` |
| `intercom_join_alert` | `ij` |
| `start_cloud_recording` | `sr` |
| `start_cloud_recording_opts` | `sro` |
| `auto_start_transcription` | `ast` |
| `enable_recording` | `er` |
| `enable_screenshare` | `ss` |
| `start_video_off` | `vo` |
| `start_audio_off` | `ao` |
| `meeting_join_hook` | `mjh` |
| `eject_at_token_exp` | `ejt` |
| `eject_after_elapsed` | `eje` |
| `lang` | `uil` |
| `enable_recording_ui` | `erui` |
| `permissions` | `p` |

## Restricting exit redirects

A self-signed token is validated by its signature alone, so any account able to sign tokens for your domain can set `rome` (`redirect_on_meeting_exit`) to any destination. Because the meeting link itself is on a `daily.co` subdomain, a participant has no visual cue that leaving the call will send them somewhere else.

If that matters for your deployment, set the [`redirect_on_meeting_exit_allowed_hosts`](/reference/rest-api/domain/set-domain-config#body-properties-redirect-on-meeting-exit-allowed-hosts) property on your domain. It is optional and unset by default, in which case any destination is permitted and behavior is unchanged. Once set, it is enforced for self-signed tokens, tokens created through the API, and the domain-level `redirect_on_meeting_exit`:

```json theme={null}
{
  "properties": {
    "redirect_on_meeting_exit_allowed_hosts": [
      "app.example.com",
      "*.example.com",
      "myapp:"
    ]
  }
}
```

A `*.` entry matches subdomains only and not the apex domain, so list both if you need both. Use a bare scheme ending in `:` to permit a mobile app deep link.

A destination that is not on the allowlist is dropped rather than rejected: the participant joins and leaves the call normally, they are just not redirected. This is worth knowing when testing, because there is no client-side error to observe.

<Note>
  Regardless of whether an allowlist is configured, exit redirects to `javascript:`, `data:`, `vbscript:`, `blob:` and `file:` URLs are always rejected.
</Note>

## Permissions abbreviations

The [`permissions`](/reference/rest-api/meeting-tokens/create-meeting-token#body-properties-permissions) property uses the following abbreviated structure:

```javascript theme={null}
{
  // permissions - all fields optional
  "p": {
    // hasPresence
    "hp": boolean,
    // canSend
    "cs": boolean | // shorthand meaning "all" or "none"
          // A string with some or all of the following values, separated by commas:
          // "v" -> "video"
          // "a" -> "audio"
          // "sv" -> "screenVideo"
          // "sa" -> "screenAudio"
          "v,a,sv,sa",
    // canReceive
    "cr": {
      // base
      "b": boolean | // shorthand meaning "all" or "none"
          {
            "v": false,  // video
            "a": true,   // audio
            "sv": false, // screenVideo
            "sa": true,  // screenAudio
            "cv": {      // customVideo
              "*": false
            },
            "ca": {      // customAudio
              "*": true
            }
          },
      // byUserId
      "u": {
        "foo": boolean | { /* ... */ } // same values as base
        // more user_ids here, or "*" for "all user_ids"
      },
      // byParticipantId
      "p": {
        "42fb115a-6d42-4155-ae4f-c96629f5217d": boolean | { /* ... */ } // same values as base
        // more participant ids here, or "*" for "all participant ids"
      }
    },
    // canAdmin
    "ca": boolean | // shorthand meaning "all" or "none"
          // A string with some or all of the following values, separated by commas:
          // "p" -> "participants"
          // "s" -> "streaming"
          // "t" -> "transcription"
          "p,s,t"
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.