Skip to content

Mint access tokens

Twilio’s client-side SDKs (Voice, Video, Conversations and Sync) authenticate with Access Tokens: short-lived JWTs your server mints so a browser or phone can talk to Twilio directly, without ever holding your account credentials.

TwilioTokenService mints them.

src/token/token.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { TwilioTokenService } from 'nestjs-twilio';
@Controller('token')
export class TokenController {
constructor(private readonly tokens: TwilioTokenService) {}
@Get('voice')
voice(@Query('identity') identity: string) {
return {
token: this.tokens.createVoiceToken({ identity, incomingAllow: true }),
};
}
}

Access Tokens are signed with an API key, never an auth token. The client you mint from must be registered with apiKey and apiSecret:

TwilioModule.forRoot({
accountSid: process.env.TWILIO_ACCOUNT_SID,
apiKey: process.env.TWILIO_API_KEY, // SK…
apiSecret: process.env.TWILIO_API_SECRET,
});

Minting from a client configured with an authToken throws a BadRequestException naming the client, rather than emitting a JWT that Twilio would reject once it reached the browser.

Method Grant Key options
createVoiceToken() Programmable Voice incomingAllow, outgoingApplicationSid, outgoingApplicationParams
createVideoToken() Programmable Video room
createChatToken() Conversations serviceSid, pushCredentialSid
createSyncToken() Sync serviceSid

Every helper accepts the shared JWT settings (identity, ttl, nbf and region) alongside its grant-specific options.

this.tokens.createVideoToken({ identity: 'alice', room: 'daily-standup' });
this.tokens.createChatToken({ identity: 'alice', serviceSid: 'ISxxxxxxxx' });
this.tokens.createSyncToken({ identity: 'alice', serviceSid: 'ISxxxxxxxx' });

TaskRouter, Playback and multi-grant tokens

Section titled “TaskRouter, Playback and multi-grant tokens”

createToken() accepts grants you build yourself. Use it for products without a dedicated helper, or to put several grants on one token:

import { jwt } from 'twilio';
this.tokens.createToken({
identity: 'alice',
grants: [
new jwt.AccessToken.VideoGrant({ room: 'daily-standup' }),
new jwt.AccessToken.ChatGrant({ serviceSid: 'ISxxxxxxxx' }),
],
});

A token with no grants is rejected. It could not access anything.

Pass a client name as the second argument to sign with a named client’s own credentials. Subaccounts carry their own API keys, so a subaccount token must be signed by that subaccount:

this.tokens.createVoiceToken({ identity: 'alice' }, 'billing');

Omit the name to use the default client.

Tokens default to one hour. Twilio caps them at 24 hours and recommends the shortest lifetime your application can tolerate, since a leaked token is valid until it expires.

this.tokens.createVideoToken({ identity: 'alice', ttl: 600 }); // 10 minutes

A ttl above 86400 is rejected at mint time. Twilio would otherwise reject the token when the client tried to use it, far from the code that set it.

The identity is how Twilio and your application identify the user, and it is what other participants see.

See TwilioTokenOptions for the shared JWT settings (identity, ttl, nbf, region) every helper accepts, and the Access Tokens reference for the full token model.