Skip to content

Commit 0f560db

Browse files
Add token source API for fetching LiveKit tokens (#177)
* Adds new public API token_source.h, allowing users to now mint tokens using the following paths: * Literal: user-provided token (basically the legacy livekit-cli minted path) * Sandbox: enable a sandbox token server via LiveKit cloud, and allow users insecurely mint tokens (development only) * Endpoint: production-level server support * Custom: additional user token minting support
1 parent 91214d9 commit 0f560db

38 files changed

Lines changed: 2599 additions & 33 deletions

.github/scripts/check_no_private_symbols.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
Verify that liblivekit's exported ABI does not leak private dependency symbols.
1818
1919
The LiveKit SDK statically links several private dependencies (spdlog, fmt,
20-
google::protobuf, absl). When those symbols escape the dynamic symbol table
20+
google::protobuf, absl, nlohmann/json). When those symbols escape the dynamic symbol table
2121
of liblivekit.{so,dylib,dll}, they collide at runtime with the same libraries
2222
loaded elsewhere in the host process (a common failure mode is ROS 2's
2323
rcl_logging_spdlog ABI-clashing with our vendored spdlog and crashing inside
@@ -52,6 +52,7 @@
5252
"fmt::v",
5353
"google::protobuf",
5454
"absl::",
55+
"nlohmann::",
5556
]
5657

5758
MAX_REPORTED_LEAKS = 20

.github/workflows/builds.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ jobs:
114114
libssl-dev \
115115
libprotobuf-dev protobuf-compiler \
116116
libabsl-dev \
117+
libcurl4-openssl-dev \
117118
libwayland-dev libdecor-0-dev
118119
119120
- name: Install deps (macOS)

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ jobs:
101101
docker-images:
102102
name: Docker Images
103103
needs: changes
104-
if: ${{ (github.event_name == 'pull_request' && needs.changes.outputs.docker == 'true') || github.event_name == 'workflow_dispatch' }}
104+
if: ${{ (github.event_name == 'pull_request' && needs.changes.outputs.docker == 'true') || (github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docker == 'true') || github.event_name == 'workflow_dispatch' }}
105105
permissions:
106106
contents: read
107107
actions: read
108108
packages: write
109109
uses: ./.github/workflows/docker-images.yml
110110
with:
111-
push_images: false
111+
push_images: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
112112
secrets: inherit
113113

114114
tests:

.github/workflows/cpp-checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
sudo apt-get install -y \
6363
build-essential cmake ninja-build pkg-config \
6464
llvm-dev libclang-dev clang \
65-
libssl-dev wget ca-certificates gnupg
65+
libssl-dev libcurl4-openssl-dev wget ca-certificates gnupg
6666
6767
- name: Install clang-tidy 19 (for ExcludeHeaderFilterRegex support)
6868
run: |

.github/workflows/docker-images.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ jobs:
200200
docker push "${base_image}:${sha_tag}-amd64"
201201
fi
202202
203+
docker tag livekit-cpp-sdk-base-x64:${{ github.sha }} "${base_image}:base-main-amd64"
204+
docker push "${base_image}:base-main-amd64"
205+
203206
- name: Push SDK image (amd64)
204207
if: ${{ inputs.push_images }}
205208
shell: bash
@@ -328,6 +331,9 @@ jobs:
328331
docker push "${base_image}:${sha_tag}-arm64"
329332
fi
330333
334+
docker tag livekit-cpp-sdk-base-arm64:${{ github.sha }} "${base_image}:base-main-arm64"
335+
docker push "${base_image}:base-main-arm64"
336+
331337
- name: Push SDK image (arm64)
332338
if: ${{ inputs.push_images }}
333339
shell: bash
@@ -523,6 +529,11 @@ jobs:
523529
"${base_image}:${sha_tag}-arm64"
524530
fi
525531
532+
docker buildx imagetools create \
533+
-t "${base_image}:base-main" \
534+
"${base_image}:base-main-amd64" \
535+
"${base_image}:base-main-arm64"
536+
526537
publish-sdk-manifest:
527538
name: Publish SDK manifest
528539
runs-on: ubuntu-latest

.github/workflows/make-release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ jobs:
116116
libssl-dev \
117117
libprotobuf-dev protobuf-compiler \
118118
libabsl-dev \
119+
libcurl4-openssl-dev \
119120
libwayland-dev libdecor-0-dev
120121
121122
- name: Install deps (macOS)

.github/workflows/tests.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ jobs:
115115
libssl-dev \
116116
libprotobuf-dev protobuf-compiler \
117117
libabsl-dev \
118+
libcurl4-openssl-dev \
118119
libwayland-dev libdecor-0-dev \
119120
jq
120121
@@ -215,7 +216,6 @@ jobs:
215216
--gtest_brief=1 `
216217
--gtest_output="xml:build-release\unit-test-results.xml"
217218
218-
# ---------- Start livekit-server for integration tests ----------
219219
- name: Start livekit-server
220220
if: matrix.e2e-testing
221221
id: livekit_server
@@ -255,12 +255,22 @@ jobs:
255255
fi
256256
lk --version
257257
258+
- name: Start token server
259+
if: matrix.e2e-testing
260+
id: token_server
261+
uses: livekit/token-server-action@a1e42c649a1998d5b224f5102f252c07762024f0 # v0.0.1
262+
with:
263+
livekit-url: ws://localhost:7880
264+
api-key: devkey
265+
api-secret: secret
266+
258267
- name: Run integration tests
259268
if: matrix.e2e-testing
260269
timeout-minutes: 10
261270
shell: bash
262271
env:
263272
RUST_LOG: "metrics=debug"
273+
LIVEKIT_CREATE_TOKEN_URL: ${{ steps.token_server.outputs.token-url }}
264274
run: |
265275
set -euo pipefail
266276
source .token_helpers/set_data_track_test_tokens.bash
@@ -272,6 +282,11 @@ jobs:
272282
shell: bash
273283
run: tail -n 500 "${{ steps.livekit_server.outputs.log-path }}" || true
274284

285+
- name: Dump token server log on failure
286+
if: failure() && matrix.e2e-testing && steps.token_server.outputs.log-path != ''
287+
shell: bash
288+
run: tail -n 200 "${{ steps.token_server.outputs.log-path }}" || true
289+
275290
# ---------- Upload results ----------
276291
- name: Upload test results
277292
if: always()
@@ -336,6 +351,7 @@ jobs:
336351
libssl-dev \
337352
libprotobuf-dev protobuf-compiler \
338353
libabsl-dev \
354+
libcurl4-openssl-dev \
339355
libwayland-dev libdecor-0-dev
340356
pip install --break-system-packages gcovr
341357

AGENTS.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Be sure to update the directory layout in this file if the directory layout chan
7777
| `examples/` | In-tree example applications |
7878
| `client-sdk-rust/` | Git submodule holding the Rust core of the SDK|
7979
| `client-sdk-rust/livekit-ffi/protocol/*.proto` | FFI contract (protobuf definitions, read-only reference) |
80-
| `cmake/` | Build helpers (`protobuf.cmake`, `spdlog.cmake`, `LiveKitConfig.cmake.in`) |
80+
| `cmake/` | Build helpers (`protobuf.cmake`, `spdlog.cmake`, `nlohmann_json.cmake`, `LiveKitConfig.cmake.in`) |
8181
| `docker/` | Dockerfile for CI and SDK distribution images |
8282
| `scripts/` | Developer / CI helper scripts (e.g. `clang-tidy.sh`) |
8383
| `docs/` | Documentation root. `docs/` holds hand-written long-form Markdown intended to also read well on GitHub. |
@@ -338,6 +338,7 @@ Adhere to clang-tidy checks configured in `.clang-tidy`. After C++ code changes,
338338
|------------|-------|-------|
339339
| protobuf | Private (built-in) | Vendored via FetchContent (Unix) or vcpkg (Windows) |
340340
| spdlog | **Private** | FetchContent or system package; must NOT leak into public API |
341+
| nlohmann/json | **Private** | Header-only; vendored via FetchContent (Unix) or vcpkg (Windows); must NOT leak into public API |
341342
| client-sdk-rust | Build-time | Git submodule, built via cargo during CMake build |
342343
| Google Test | Test only | FetchContent in `src/tests/CMakeLists.txt` |
343344

@@ -356,7 +357,7 @@ Tests are under `src/tests/` using Google Test:
356357
cd build-debug && ctest
357358
```
358359

359-
Integration tests (`src/tests/integration/`) cover: room connections, callbacks, data tracks, RPC, logging, audio processing, and the subscription thread dispatcher.
360+
Integration tests (`src/tests/integration/`) cover: room connections, callbacks, data tracks, RPC, logging, audio processing, and the subscription thread dispatcher. The token source HTTP/JSON wire contract (request serialization, response parsing, header passthrough, GET support, sandbox URL/header resolution) is covered by mocked unit tests in `src/tests/unit/test_token_source.cpp`, which inject a stub HTTP transport so no live server is needed. For a full end-to-end check, `TokenSourceEndpointConnectTest` connects a `Room` with a real JWT minted by the `livekit/token-server-action` token server pointed at the local dev `livekit-server`. The action exposes its `/createToken` endpoint as a `token-url` output; `tests.yml` passes that to the integration test step as `LIVEKIT_CREATE_TOKEN_URL`, which the test reads to locate the endpoint. The server is started in the `e2e-testing` jobs via the token server's reusable GitHub Action, pinned by SHA in `tests.yml`.
360361

361362
When adding new client facing functionality, add a new test case to the existing test suite.
362363
When adding new client facing functionality, add benchmarking to understand the limitations of the new functionality.
@@ -401,6 +402,13 @@ all filtered stages; normal pull requests and pushes use the path filters.
401402
- `.github/workflows/docker-images.yml` — Reusable Docker image smoke-test and
402403
publish workflow (optional push via input), called by CI and release workflows.
403404

405+
The `tests.yml` e2e jobs consume two external, pinned composite actions:
406+
`livekit/dev-server-action` (local `livekit-server`) and
407+
`livekit/token-server-action` (a real `/createToken` endpoint used by
408+
`TokenSourceEndpointConnectTest`). Both are referenced by commit SHA. The token
409+
server action lives in its own repo on purpose — it is general-purpose like
410+
`dev-server-action` and is not bundled here.
411+
404412
When adding or renaming files that affect a CI stage, update the matching
405413
`ci.yml` `changes` filter in the same PR. For example, new build scripts,
406414
CMake files, package manifests, or reusable build workflows should be added to

CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ file(MAKE_DIRECTORY ${PROTO_BINARY_DIR})
9393
include(protobuf)
9494
# spdlog logging library (PRIVATE dependency).
9595
include(spdlog)
96+
# nlohmann/json header-only library (PRIVATE dependency).
97+
include(nlohmann_json)
9698
# Ensure protoc executable is found.
9799
if(TARGET protobuf::protoc)
98100
set(Protobuf_PROTOC_EXECUTABLE "$<TARGET_FILE:protobuf::protoc>")
@@ -392,6 +394,11 @@ add_library(livekit SHARED
392394
src/room_proto_converter.cpp
393395
src/room_proto_converter.h
394396
src/subscription_thread_dispatcher.cpp
397+
src/token_source.cpp
398+
src/token_source_http.cpp
399+
src/token_source_json.cpp
400+
src/token_source_jwt.cpp
401+
src/token_source_internal.h
395402
src/local_participant.cpp
396403
src/remote_participant.cpp
397404
src/stats.cpp
@@ -457,10 +464,18 @@ target_include_directories(livekit SYSTEM PRIVATE
457464
target_link_libraries(livekit
458465
PRIVATE
459466
spdlog::spdlog
467+
nlohmann_json::nlohmann_json
460468
livekit_ffi
461469
${LIVEKIT_PROTOBUF_TARGET}
462470
)
463471

472+
if(WIN32)
473+
target_link_libraries(livekit PRIVATE winhttp)
474+
else()
475+
find_package(CURL REQUIRED)
476+
target_link_libraries(livekit PRIVATE CURL::libcurl)
477+
endif()
478+
464479
target_compile_definitions(livekit
465480
PRIVATE
466481
SPDLOG_ACTIVE_LEVEL=${_SPDLOG_ACTIVE_LEVEL}

CMakePresets.json

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@
9494
"cacheVariables": {
9595
"CMAKE_BUILD_TYPE": "Release",
9696
"LIVEKIT_BUILD_EXAMPLES": "ON",
97-
"LIVEKIT_BUILD_TESTS": "OFF",
98-
"VCPKG_MANIFEST_FEATURES": "examples"
97+
"LIVEKIT_BUILD_TESTS": "OFF"
9998
}
10099
},
101100
{
@@ -107,8 +106,7 @@
107106
"cacheVariables": {
108107
"CMAKE_BUILD_TYPE": "Debug",
109108
"LIVEKIT_BUILD_EXAMPLES": "ON",
110-
"LIVEKIT_BUILD_TESTS": "OFF",
111-
"VCPKG_MANIFEST_FEATURES": "examples"
109+
"LIVEKIT_BUILD_TESTS": "OFF"
112110
}
113111
},
114112
{
@@ -216,8 +214,7 @@
216214
"cacheVariables": {
217215
"CMAKE_BUILD_TYPE": "Release",
218216
"LIVEKIT_BUILD_EXAMPLES": "ON",
219-
"LIVEKIT_BUILD_TESTS": "ON",
220-
"VCPKG_MANIFEST_FEATURES": "examples"
217+
"LIVEKIT_BUILD_TESTS": "ON"
221218
}
222219
},
223220
{
@@ -229,8 +226,7 @@
229226
"cacheVariables": {
230227
"CMAKE_BUILD_TYPE": "Debug",
231228
"LIVEKIT_BUILD_EXAMPLES": "ON",
232-
"LIVEKIT_BUILD_TESTS": "ON",
233-
"VCPKG_MANIFEST_FEATURES": "examples"
229+
"LIVEKIT_BUILD_TESTS": "ON"
234230
}
235231
},
236232
{

0 commit comments

Comments
 (0)