Boost what matters

Feature Requests

Submit feature requests and boost what you want to see next.

#5589

Support resource-scoped Access Tokens from SpacetimeAuth (OIDC flow)

RequestedJul 26, 2026

## Summary Add support for SpacetimeAuth to mint Access Tokens that follow standard OIDC/OAuth 2.0 practices when connecting to SpacetimeDB modules. Currently SpacetimeDB expects (and documents) the use of ID Tokens for WebSocket connections. While this works and simplifies bring-your-own-issuer (BYOI) scenarios, it diverges from the intended use of ID Tokens vs Access Tokens and creates friction for client developers. [Original Discord discussion](https://discord.com/channels/1037340874172014652/1138987509834059867/1530000822551969973) ## The Problem - ID Tokens are intended for the client application (Relying Party) to verify identity (`aud` = `client_id`). - Access Tokens are intended for resource servers (SpacetimeDB host) to authorize access (`aud` = resource URI). - When a client opens a WebSocket connection and presents a token, SpacetimeDB is acting as a resource server. Presenting an ID Token in this context re-purposes it for authorization. - SpacetimeAuth Access Tokens currently lack useful claims (e.g. `steam_owned_games`, user metadata) and a proper resource audience, forcing special-casing in client code. This makes it harder to write clean, uniform auth code that follows standard OIDC library patterns. ## Proposed Solution Add support in SpacetimeAuth for a resource-audience / resource parameter on the token endpoint (aligned with [RFC 8707 – Resource Indicators for OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc8707)). **Desired Behavior** - Client can request a token with an audience, e.g.: `audience=https://maincloud.spacetimedb.com` - SpacetimeAuth issues an Access Token with: - `aud` set to the requested resource (the SpacetimeDB host / module URI) - `azp` (or a `client_id` claim) containing the original client identifier - Useful custom claims currently only present on ID Tokens (e.g. `steam_owned_games`) - SpacetimeDB (or the connection layer) can validate the `aud` claim as a standard resource check. Module code can still inspect other claims for application-specific authorization. ### Benefits - Aligns with OpenID Connect Core, RFC 6749, RFC 9700 (Security BCP), and RFC 8707. - Removes the need for provider-specific branching in client code. - Keeps full BYOI support (ID Tokens remain available as a fallback for issuers that don’t support custom audiences, e.g. Firebase, or raw non-OIDC tokens like Discord/GitHub). - Improves developer experience when using standard OIDC libraries. ## Compatibility Notes When SpacetimeAuth is used as the issuer (or as a broker), we can follow the OIDC spec cleanly. For third-party / non-standard issuers that cannot issue resource-scoped tokens, the existing ID Token path can continue to work. Supporting the standard Access Token flow for SpacetimeAuth (and other compliant OIDC providers such as Auth0, Cognito, etc.) covers the vast majority of use cases without breaking BYOI. ## Additional Context / References - [OpenID Connect Core 1.0 – ID Token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) - [RFC 6749 §1.4 – Access Token](https://datatracker.ietf.org/doc/html/rfc6749#section-1.4) - [RFC 9700 – OAuth 2.0 Security Best Current Practice](https://www.rfc-editor.org/info/rfc9700) - [RFC 8707 – Resource Indicators for OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc8707) - [Auth0](https://auth0.com/blog/id-token-access-token-what-is-the-difference/) / [Duende](https://duendesoftware.com/learn/the-key-differences-when-using-access-tokens-vs-id-tokens-in-web-app-architecture) documentation on ID Token vs Access Token usage Happy to help test, provide more examples, or refine the design.

6,000TeV
From 1 booster
#5588

B-tree indexes on non-unit (payload-carrying) enums

RequestedJul 26, 2026

**Summary** Allow #[index(btree)] (and multi-column indexes) on enums that carry data, not just unit/C-style enums. [Discord conversation](https://discord.com/channels/1037340874172014652/1138987509834059867/1530939373913247854) **Motivation / Use case** A very common pattern is an “intent” or “state” enum that sometimes references another entity: ```rust #[derive(SpacetimeType)] pub enum MoveIntent { Path(WorldPos), Position(WorldPos), Direction(u8), ChaseAttack(ActorId), // ← want to find all rows where this == some ActorId } #[table(accessor = move_state_tbl)] pub struct MoveState { pub intent: MoveIntent, #[primary_key] pub actor_id: ActorId, pub zone: ZoneName, } ``` When an actor leaves a zone I need to efficiently find every other actor that is currently chasing them (MoveIntent::ChaseAttack(their_id)) and clear those move states. **Current work-arounds** 1. Full table scan (.iter() + filter) — simple but O(n). 2. Manually pack the enum into two columns (kind: u8 + payload: u32) and put a multi-column B-tree on them. 3. Maintain a separate “chasers” table with its own index on target_id. All three work, but they either cost performance or force awkward denormalisation. **Suggested behaviour** Ideally the index would support both: - Equality on a whole variant: intent.filter(MoveIntent::ChaseAttack(id)) - Or at least equality / range on the payload of a specific variant (the most useful part for this pattern). Even a restricted form that only lets you index “the payload of variant X” would already solve the majority of real-world cases.

2TeV
From 1 booster
#5577

Ergonomic Partial Updates via AsChangeset Macro

RequestedJul 22, 2026

I’d like to request a quality-of-life feature for partial row update requests, similar to Diesel’s [#[derive(AsChangeset)]](https://docs.diesel.rs/master/diesel/query_builder/derive.AsChangeset.html) macro. **To be clear up front**: I am not asking for column-level mutations at the storage layer. I know SpacetimeDB currently requires whole-row operations under the hood. Rather, this is a request for a DX wrapper to hide the boilerplate of requesting an update to specific fields while preserving the rest of the row. Currently, modifying a single field requires a manual "read-modify-write" pattern in user-land, meaning we have to execute a `find()` query first just to preserve the unmodified data. A macro could generate a changeset struct where non-primary-key fields are wrapped in `Option<T>`. This would allow us to call an `update_changeset` method, and the host (or a generated wrapper) would handle fetching the old row, applying the `Some` values, and writing the full row back. This eliminates the boilerplate of the initial read query, allows for clean `..Default::default()` syntax when updating large tables, and potentially offers a minor performance perk by removing user-land boundary crossing. ```rust // CURRENT: Requires a read to avoid overwriting `zone` let prev = ctx.db.locality_tbl().actor_id().find(actor_id).unwrap(); ctx.db.locality_tbl().actor_id().update(Locality { actor_id, chunk_x: new_x, chunk_z: new_z, zone: prev.zone, }); // PROPOSED: Using a generated changeset struct ctx.db.locality_tbl().actor_id().update_partial(LocalityChangeset { actor_id, chunk_x: Some(new_x), chunk_z: Some(new_z), ..Default::default() // `zone` defaults to None and is untouched }); ``` **Table definition with macro** ```rust #[table(accessor = locality_tbl)] #[derive(AsChangeset)] pub struct Locality { #[primary_key] pub actor_id: ActorId, pub zone: ZoneName, pub chunk_x: i8, pub chunk_z: i8, } // ...which would automatically yield: pub struct LocalityChangeset { pub actor_id: ActorId, pub zone: Option<ZoneName>, pub chunk_x: Option<i8>, pub chunk_z: Option<i8>, } ```

1TeV
From 1 booster
#5425

Support custom structs as primary keys

RequestedJun 22, 2026

Allow custom structs marked with `[SpacetimeDB.Type]` to be used as primary keys when they wrap a SpacetimeDB-supported primary-key type. For example: ```csharp [SpacetimeDB.Type] public partial struct ItemKey { public ulong Value; public bool IsReserved() public ItemCategory GetItemCategory() public static implicit operator ulong(ItemKey key) => key.Value; public static implicit operator ItemKey(ulong value) => new() { Value = value }; } [SpacetimeDB.Table(Accessor = "Item", Public = true)] public partial struct Item { [SpacetimeDB.PrimaryKey] public ItemKey Key; public string Name; } ``` ## Why? Custom key types make it possible to attach arbitrary methods directly to a key. This also could help prevent different kinds of keys from being mixed together accidentally, even when they use the same underlying type. Without this support, the table field must use a built-in type, and the user has to repeatedly convert between that type and the custom struct before calling methods or passing the key to other parts of the application. ## Proposed behavior A struct marked with `[SpacetimeDB.Type]` should be usable as a primary key, unique key, or single-column index key **when it wraps exactly one SpacetimeDB-supported primary-key type**. It would be acceptable to require implicit conversions and/or to and from the supported type. Alternatively, a dedicated attribute or other explicit way to identify the underlying key type would be reasonable. SpacetimeDB could store and index the value using the supported underlying type, while generated APIs continue to use the custom struct.

1,002TeV
From 2 boosters