Skip to content
103 changes: 102 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ const room = new Room({
},
});

// get your url from livekit's dashboard, or point it at a self hosted livekit deployment
const url = "ws://localhost:7800";

// generate a token by making a request to a endpoint using the livekit server sdk or
// using a prebuilt TokenSource (documented below)
const token = "...";

// pre-warm connection, this can be called as early as your page is loaded
room.prepareConnection(url, token);

Expand All @@ -107,7 +114,7 @@ room
.on(RoomEvent.LocalTrackUnpublished, handleLocalTrackUnpublished);

// connect to room
await room.connect('ws://localhost:7800', token);
await room.connect(url, token);
console.log('connected to room', room.name);

// publish local camera and mic tracks
Expand Down Expand Up @@ -304,6 +311,100 @@ setLogExtension((level: LogLevel, msg: string, context: object) => {
});
```

### Generating a url/token with `TokenSource`

A pre-implemented set of credentials fetching utilities. Once one is constructed, call `fetch` on
to generate a new set of credentials.

There are two types of `TokenSource`'s - fixed and configurable. Configurable token sources can be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if that makes sense to mention which use cases fixed tokenSources and configurable tokenSource are used for ? assuming they should be used by different use cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was kinda thinking the table would accomplish that, but maybe it would be worth having an explicit paragraph / callout with some examples?

passed options as part of the generation process, allowing your to customize the token that they
generate. Fixed token sources generate their credentials fully indepentantly and don't allow for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indepentantly -> independently

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wonder if this will be slightly more clear:
Fixed token sources generate static or pre-generated credentials and do not accept parameters when fetching

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I went for something somewhere in between.

output customization.

```ts
// Fixed token sources don't take any parameters as part of `fetch`:
const fixed: TokenSourceFixed = /* ... */;
const fixedResponse = await fixed.fetch();
room.connect(fixedResponse.serverUrl, fixedResponse.participantToken);

// Configurable token sources can optionally take parameters to change what is encoded into the token:
const configurable: TokenSourceConfigurable = /* ... */;
const configurableResponse = await configurable.fetch({ agentName: "agent to dispatch" } /* <-- here */);
room.connect(configurableResponse.serverUrl, configurableResponse.participantToken);
```

|Mechanism: | using pre-generated credentials | via a http request to a url | via fully custom logic |
|-------------|--|--|--|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this line ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be there for the markdown table formatting to work properly. I'll make myself a note before merging to add the proper number of dashes though (not important for markdown to parse it properly, but I think this might be what you are getting at)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with either option.

|Fixed | [`TokenSource.literal`](#tokensourceliteral) | &mdash; | [`TokenSource.literal(async () => { /* ... */ })`](#tokensourceliteral) |
|Configurable | &mdash; | [`TokenSource.endpoint`](#tokensourceendpoint) or [`TokenSource.sandboxTokenServer`](#tokensourceendpoint) | [`TokenSource.custom`](#tokensourcecustom) |

Comment on lines +335 to +340
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to call out this table - not sure if it's in the right place exactly in the flow of the broader content, but IMO it's super useful to visualize them all like this and it would be great to have this in the final docs pages as well!

#### TokenSource.Literal
A fixed token source which returns a static set of credentials or a computed set of credentials
with no external input on each call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, with no external input required on each call

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the change, but reading it through I'm still not super pleased with the wording on this one, I'l going to think some more about it.


Example:
```ts
const literal1 = TokenSource.literal({ serverUrl: "ws://localhost:7800", participantToken: "..." });
await literal1.fetch() // { serverUrl: "ws://localhost:7800", participantToken: "..." }

const literal2 = TokenSource.literal(async () => ({ serverUrl: "ws://localhost:7800", participantToken: "..." }));
await literal2.fetch() // { serverUrl: "ws://localhost:7800", participantToken: "..." }
```

#### TokenSource.Endpoint
A configurable token source which makes a request to an endpoint to generate credentials. By
default, a `POST` request with a `Content-Type: application/json` header is made, and the request
body is expected to follow the [standard token format](FIXME: add docs link here!). If
credentials generation is successful, the endpoints returns a 2xx status code with a body following
the [standard token response format](FIXME: add docs link here!).
Copy link
Contributor Author

@1egoman 1egoman Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to call out: there are some placeholder links that I think would be good to point to a docs page talking about the standard token format.

In effect I think this could contain a more wordsmithed version of https://github.com/livekit-examples/token-server-status/pull/33, probably also linking to https://cloud.livekit.io/projects/p_/sandbox/templates/token-server somewhere in there too.

I can take a pass at this if desired but I think it's probably pretty self explanatory (the content in the pull request body plus maybe an example or two). One small detail not in the pull request that would be good to include is that there are typescript types that can be used if writing a node server endpoint here and it would be good to make those known.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the placeholder links to https://cloud.livekit.io/projects/p_/sandbox/templates/token-server, which should render the correct docs after this is merged.


Example:
```ts
const endpoint1 = TokenSource.endpoint("http://example.com/credentials-endpoint");
await endpoint1.fetch({ agentName: "agent to dispatch" }) // { serverUrl: "...", participantToken: "... token encoding agentName ..." }

const endpoint2 = TokenSource.endpoint("http://example.com/credentials-endpoint", {
// For all supported options below, see https://developer.mozilla.org/en-US/docs/Web/API/RequestInit
method: "PUT",
headers: {
"X-Custom-Header": "custom header value",
},
});
await endpoint2.fetch({ agentName: "agent to dispatch" }) // { serverUrl: "...", participantToken: "... token encoding agentName ..." }
```

#### TokenSource.SandboxTokenServer
A configurable token source which makes a request to a
[sandbox token server endpoint](https://cloud.livekit.io/projects/p_/sandbox/templates/token-server),
a LiveKit-hosted token generation mechanism. This is an inherently insecure token generation
mechanism and should only be used for prototyping / NOT used in production.

One parameter is required - the sandbox id from the dashboard. This is the `token-server-xxxxxx`
value in `https://token-server-xxxxxx.sandbox.livekit.io`.

Example:
```ts
const sandbox = TokenSource.sandboxTokenServer("token-server-xxxxxx");
await sandbox.fetch({ agentName: "agent to dispatch" }); // { serverUrl: "...", participantToken: "... token encoding agentName ..." }
```

#### TokenSource.Custom
A fully custom configurable token source that allows one to consume any end application-specific
token generation mechanism.

Note that it is expected that all options passed into `fetch` will always be encoded into the
output token. If you'd rather implement a fixed version of this TokenSource, see
`TokenSource.literal(async () => { /* ... */ })`.

Example:
```ts
const sandbox = TokenSource.custom(async (options) => {
// generate token info via custom means here
return { serverUrl: "...", participantToken: "... options encoded in here ..." };
});
await sandbox.fetch({ agentName: "agent to dispatch" });
```

### RPC

Perform your own predefined method calls from one participant to another.
Expand Down
Loading