-
Notifications
You must be signed in to change notification settings - Fork 208
Add a TokenSource crate to the Rust SDKs #1274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
de3ad8b
62acd1e
7aed81a
887c543
549af2a
e0ee667
ac7a5d4
64a70f1
227ee41
6c140b5
9d09a40
b1184d6
5f01afa
ef3e095
a62d679
4ce0386
5a431bd
73e7889
9f7aa9c
97a8299
fa16788
c02c171
25ff41e
fc4e8ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| livekit-token-source: patch | ||
| --- | ||
|
|
||
| Add a TokenSource crate to the Rust SDKs - #1274 (@MaxHeimbrock) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| livekit-token-source: minor | ||
| --- | ||
|
|
||
| Add the `livekit-token-source` crate: token sources for procuring LiveKit credentials, mirroring the JS SDK's `TokenSource` — `literal`, `endpoint` (standard token endpoint format), and `development_token_server`, plus `TokenSourceFixed` / `TokenSourceConfigurable` traits for custom backends. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| [package] | ||
| name = "token_source" | ||
| version = "0.1.0" | ||
| edition.workspace = true | ||
| publish = false | ||
|
|
||
| [dependencies] | ||
| livekit-token-source = { workspace = true, features = ["rustls-tls-native-roots"] } | ||
| tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } | ||
| async-trait = "0.1" | ||
| serde_json = { workspace = true } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| use async_trait::async_trait; | ||
| use livekit_token_source::{ | ||
| TokenSourceConfigurable, TokenSourceFetchOptions, TokenSourceFixed, TokenSourceResponse, | ||
| TokenSourceResult, | ||
| }; | ||
|
|
||
| /// An example for a custom token source that reads credentials from a JSON file, e.g. | ||
| /// `{"server_url": "wss://...", "participant_token": "..."}`. | ||
| struct FileTokenSource { | ||
| path: std::path::PathBuf, | ||
| } | ||
|
|
||
| #[async_trait] | ||
| impl TokenSourceFixed for FileTokenSource { | ||
| async fn fetch(&self) -> TokenSourceResult<TokenSourceResponse> { | ||
| let contents = std::fs::read_to_string(&self.path).map_err(serde_json::Error::io)?; | ||
| let response = serde_json::from_str(&contents)?; | ||
| Ok(response) | ||
| } | ||
| } | ||
|
|
||
| #[tokio::main] | ||
| async fn main() { | ||
| // A literal token source returns a fixed set of pre-provisioned credentials. | ||
| let literal = | ||
| livekit_token_source::literal("wss://example.livekit.cloud", "<a pre-generated token>"); | ||
| match literal.fetch().await { | ||
| Ok(response) => println!( | ||
| "literal: server_url={} participant_token={}", | ||
| response.server_url, response.participant_token | ||
| ), | ||
| Err(error) => eprintln!("literal fetch failed: {error}"), | ||
| } | ||
|
|
||
| // A custom token source can procure credentials from anywhere; this one | ||
| // reads them from a JSON file next to this example's Cargo.toml. | ||
| let file_source = | ||
| FileTokenSource { path: concat!(env!("CARGO_MANIFEST_DIR"), "/token.txt").into() }; | ||
| match file_source.fetch().await { | ||
| Ok(response) => println!( | ||
| "file: server_url={} participant_token={}", | ||
| response.server_url, response.participant_token | ||
| ), | ||
| Err(error) => eprintln!("file fetch failed: {error}"), | ||
| } | ||
|
|
||
| // The remaining sources query LiveKit's development token server, which | ||
| // requires the ID of a sandbox created in your LiveKit Cloud project. | ||
| let sandbox_id = "your sandbox id".to_string(); | ||
|
|
||
| let options = TokenSourceFetchOptions::new() | ||
| .with_room_name("example-room") | ||
| .with_participant_identity("example-user"); | ||
|
|
||
| // Development token server: for prototyping only, NOT for production use. | ||
| let development_token_server = | ||
| livekit_token_source::development_token_server(sandbox_id.clone()); | ||
| match development_token_server.fetch(&options).await { | ||
| Ok(response) => println!( | ||
| "development token server: server_url={} participant_token={}", | ||
| response.server_url, response.participant_token | ||
| ), | ||
| Err(error) => eprintln!("development token server fetch failed: {error}"), | ||
| } | ||
|
|
||
| // Endpoint: POSTs the fetch options to a token endpoint using the standard | ||
| // format; here pointed at the same development token server. | ||
| let endpoint = livekit_token_source::endpoint( | ||
| "https://cloud-api.livekit.io/api/v2/sandbox/connection-details", | ||
| ) | ||
| .with_header("X-Sandbox-ID", sandbox_id); | ||
| match endpoint.fetch(&options).await { | ||
| Ok(response) => println!( | ||
| "endpoint: server_url={} participant_token={}", | ||
| response.server_url, response.participant_token | ||
| ), | ||
| Err(error) => eprintln!("endpoint fetch failed: {error}"), | ||
| } | ||
| } | ||
|
MaxHeimbrock marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"server_url": "url from file", "participant_token": "token from file"} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: maybe this should be called |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| [package] | ||
| name = "livekit-token-source" | ||
| description = "Token sources for the LiveKit Rust SDK" | ||
| version = "0.1.0" | ||
| license.workspace = true | ||
| edition.workspace = true | ||
| repository.workspace = true | ||
| readme = "README.md" | ||
|
|
||
| [features] | ||
| # By default no TLS is enabled; pick one of the TLS features below. | ||
| default = ["native-tokio"] | ||
|
|
||
| # Backend bundles — pass-throughs to livekit-net. With none enabled the crate is | ||
| # backend-blind: the host must register a client via `livekit_net::set_http_client`. | ||
| native-tokio = ["livekit-net/native-tokio"] | ||
| native-async = ["livekit-net/native-async"] | ||
| native-dispatcher = ["livekit-net/native-dispatcher"] | ||
|
|
||
| # TLS pass-throughs (only meaningful with a native backend). See livekit-api's | ||
| # Cargo.toml for guidance on choosing one, notably in container deployments. | ||
| native-tls = ["livekit-net/native-tls"] | ||
| native-tls-vendored = ["livekit-net/native-tls-vendored"] | ||
| rustls-tls-native-roots = ["livekit-net/rustls-tls-native-roots"] | ||
| rustls-tls-webpki-roots = ["livekit-net/rustls-tls-webpki-roots"] | ||
|
|
||
| [dependencies] | ||
| async-trait = "0.1" | ||
| livekit-net = { workspace = true } | ||
| serde = { workspace = true, features = ["derive"] } | ||
| serde_json = { workspace = true } | ||
| thiserror = { workspace = true } | ||
|
|
||
| [dev-dependencies] | ||
| tokio = { workspace = true, features = ["rt", "macros"] } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # LiveKit Token Source | ||
|
|
||
| Token sources for the LiveKit Rust SDK. A token source procures the credentials — server URL and | ||
| participant token — needed to join a LiveKit room. | ||
|
|
||
| Three sources ship with the crate, constructed via factory functions: | ||
|
|
||
| - `literal` — a fixed set of pre-provisioned credentials. | ||
| - `endpoint` — fetches credentials from a token endpoint implementing the | ||
| [standard format](https://docs.livekit.io/frontends/build/authentication/endpoint/). | ||
| - `development_token_server` — queries a LiveKit | ||
| [development token server](https://docs.livekit.io/frontends/build/authentication/sandbox-token-server/) | ||
| for prototyping. **Not for production use.** | ||
|
|
||
| Custom credential backends can implement the `TokenSourceFixed` or `TokenSourceConfigurable` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Add a section here on the difference between
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (IMO I still think this is worth doing) |
||
| traits. | ||
|
|
||
| ```rust | ||
| use livekit_token_source::{TokenSourceConfigurable, TokenSourceFetchOptions}; | ||
|
|
||
| let source = livekit_token_source::endpoint("https://example.com/api/token"); | ||
| let options = TokenSourceFetchOptions::new() | ||
| .with_room_name("my-room") | ||
| .with_participant_identity("user-123"); | ||
| let response = source.fetch(&options).await?; | ||
| // connect with response.server_url / response.participant_token | ||
| ``` | ||
|
|
||
| See [examples/token_source](../examples/token_source) for a runnable example. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // Copyright 2026 LiveKit, Inc. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| /// Errors returned when procuring credentials from a token source. | ||
| #[derive(Debug, thiserror::Error)] | ||
| pub enum TokenSourceError { | ||
|
MaxHeimbrock marked this conversation as resolved.
|
||
| #[error("no HTTP client available; enable a livekit-net backend feature or call livekit_net::set_http_client")] | ||
| TransportNotConfigured, | ||
|
|
||
| #[error("failed to fetch token: {0}")] | ||
| Transport(#[from] livekit_net::TransportError), | ||
|
|
||
| #[error("failed to serialize request / parse response: {0}")] | ||
| Json(#[from] serde_json::Error), | ||
|
|
||
| #[error("token server returned {status}: {body}")] | ||
| Server { status: u16, body: String }, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Copyright 2026 LiveKit, Inc. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| //! Token sources for the LiveKit Rust SDK. | ||
| //! | ||
| //! A token source procures the credentials — server URL and participant | ||
| //! token — needed to join a LiveKit room. Construct one via the | ||
| //! [`literal`] / [`endpoint`] / [`development_token_server`] factory | ||
| //! functions, or implement [`TokenSourceFixed`] / [`TokenSourceConfigurable`] | ||
| //! to plug in a custom credential backend. | ||
|
|
||
| mod error; | ||
| mod request; | ||
| mod response; | ||
| mod token_source; | ||
|
|
||
| pub use error::TokenSourceError; | ||
| pub use request::TokenSourceFetchOptions; | ||
| pub use response::TokenSourceResponse; | ||
| pub use response::TokenSourceResult; | ||
| pub use token_source::development_token_server; | ||
| pub use token_source::endpoint; | ||
| pub use token_source::literal; | ||
| pub use token_source::TokenSourceConfigurable; | ||
| pub use token_source::TokenSourceDevelopmentTokenServer; | ||
| pub use token_source::TokenSourceEndpoint; | ||
| pub use token_source::TokenSourceFixed; | ||
| pub use token_source::TokenSourceLiteral; |
Uh oh!
There was an error while loading. Please reload this page.