Auth Providers
The auth provider components under RisingTideProviders - RisingTideAuthProvider, AppModeProvider, ModeGate and ConditionalProviders.
RisingTideProviders mounts everything on this page for you. The components are documented for apps that compose the stack by hand and for reading the shipped order.
RisingTideAuthProvider
The lower-level auth composition. It takes the app's SDK client and the inner ProtocolUserConfig, and must be inside PrivyProvider.
import { PrivyProvider } from "@privy-io/react-auth";
import { RisingTideAuthProvider } from "@rising-tide/ui/auth";
<PrivyProvider appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID!}>
<RisingTideAuthProvider
sdk={rtClient}
userConfig={{
storagePrefix: "myapp",
linkInviteCodes: true,
onSignupComplete: () => {},
}}
>
{children}
</RisingTideAuthProvider>
</PrivyProvider>| Prop | Required | Purpose |
|---|---|---|
sdk | yes | The app's RisingTideSDK instance |
userConfig | yes | ProtocolUserConfig: storagePrefix, linkInviteCodes and onSignupComplete are required; onSignOut and appId are optional |
storagePrefix | no | Namespace for the auth-method and app-mode storage keys. Default rt |
appName | no | Shown by ModeGate on the maintenance and coming-soon screens |
modeLoadingComponent | no | Retained for API compatibility; maintenance needs no loading state |
It composes, outermost first: AuthMethodProvider -> InviteCodeProvider -> AppModeProvider -> ModeGate -> ConditionalProviders -> ProtocolUserProvider. The inner ProtocolUserProvider is what:
- reads the Privy access token (or the wallet's signed challenge) and attaches it to the SDK client
- creates the user record on first sign-in (
POST /api/users), through the welcome dialog when the app mounts one - resolves the viewer's
stxAddressand flattens their roles to anentitlementslist - exposes all of it through
useProtocolUser()
AppModeProvider
Holds the app's operational mode. The mode has two sources and one precedence rule: the operator-set App.mode served on GET /api/apps/{id}/config wins when it is set, in both directions - an app can be flipped into or out of maintenance without a redeploy; when the server value is null, the compiled NEXT_PUBLIC_APP_MODE holds; when the config cannot be read, the last-known server value (cached in local storage) holds, else the env.
<AppModeProvider storagePrefix="myapp" sdk={rtClient} appId={42}>
{children}
</AppModeProvider>All three props are optional. Without sdk and an app id (the prop or NEXT_PUBLIC_APP_ID) the provider never asks the server and the env value is the whole answer - which is what RisingTideProviders does for an app with no modeGate, so an ungated app holds no connection open for a question nothing acts on.
Modes (NEXT_PUBLIC_APP_MODE, default live):
| Mode | Behavior |
|---|---|
live | Normal operation |
maintenance | Shows a maintenance screen |
coming-soon | Shows a pre-launch splash |
The mode is operational only. Whether signup requires an invite is a separate, server-driven concern - the App.requireInviteForSignup flag, read via apps.getConfig and surfaced as useProtocolUser().requiresInvite. Whether a viewer may be in the app at all is the entry curtain's question, on Providers.
ModeGate
Gates the app on the operational mode - it renders the maintenance or coming-soon screen when one is set, otherwise the app. Pass the app name for those screens.
<ModeGate appName="My App">
{children}
</ModeGate>ConditionalProviders
Composes PrivyTokenProvider (enabled only when the session's auth method is privy) and StacksProvider into a single wrapper. PrivyStateSync, which mirrors Privy's session state into the protocol user context, is mounted by ProtocolUserProvider itself. Used internally by the auth layer - apps use RisingTideProviders or RisingTideAuthProvider instead.