React Quickstart
Recommended browser integration using useTcmOAuth with automatic popup or redirect selection.
SDK snapshot 21344f2c
Use useTcmOAuth when your app already has a server route for exchange and you want the SDK to choose popup vs redirect automatically.
Basic Usage
import { useTcmOAuth } from "@crimsoncorp/oauth-react";
export function LoginActions() {
const oauth = useTcmOAuth<{ userId: string }>({
clientId: process.env.NEXT_PUBLIC_TCM_CLIENT_ID!,
tcmWebUrl: process.env.NEXT_PUBLIC_TCM_OAUTH_WEB_URL!,
exchangeEndpoint: "/api/auth/tcm/oauth-exchange",
callbackPath: "/auth/tcm/callback",
interactionMode: "auto",
onSuccess: ({ userId }) => {
console.log("Logged in", userId);
},
onError: (error) => {
console.error(error.code, error.message);
},
});
return (
<>
<button onClick={() => void oauth.startLogin()} disabled={oauth.authenticating}>
{oauth.authenticating ? "Please wait..." : "Open provider chooser"}
</button>
<button onClick={() => void oauth.startLogin("discord")} disabled={oauth.authenticating}>
Continue with Discord
</button>
</>
);
}startLogin() opens the TCM provider chooser with prompt=select_provider. startLogin("discord") or another provider value forces that provider with provider=<provider>&prompt=login.
If the app should always start Google immediately, set googleOnly: true and call startLogin() without a provider argument.
Migrating to 1.3.0
startLogin(provider) now carries provider intent through the OAuth authorize request. Use it only when the app must require that provider, for example startLogin("twitch") for a Twitch-gated admin tool.
If your app previously passed a provider only to influence the initial UI, switch to startLogin() so the user gets the provider chooser.
Scopes
Omit scope when the OAuth client has one allowed scope in the Developers portal. The SDK will resolve that client policy before starting login.
If the client is allowed to request multiple scope sets, pass an explicit value such as scope: "profile email" or the narrowest scope set your app needs. The requested scopes must already be allowed on the OAuth client, otherwise the OAuth server will reject the authorization request.
Return Shape
The hook returns:
authenticatingphaseerrorresolvedInteractionModestartLogin(provider)clearError()
resolvedInteractionMode becomes "popup" or "redirect" once the SDK decides which path it is taking.
Interaction Modes
useTcmOAuth supports:
interactionMode: "auto" | "popup" | "redirect"Recommended default:
interactionMode: "auto"Behavior:
autochooses popup on desktop-like environmentsautochooses redirect on mobile-like environments- if popup opening is blocked, the SDK falls back to redirect by default
You can disable popup fallback with:
fallbackToRedirect: falseIf you want a specific post-login landing route for redirect flows:
returnTo: "/account"Diagnostics
By default, route-backed exchange requests send x-tcm-flow-id and x-tcm-message-id in development and staging. Override with:
diagnostics: "always"
diagnostics: "never"Callback Page
Render the SDK callback component on your app origin:
import { TcmOAuthCallbackPage } from "@crimsoncorp/oauth-react";
export default function Page() {
return <TcmOAuthCallbackPage />;
}Recommended path:
"/auth/tcm/callback"Low-Level Alternative
If you need full control over the exchange request, use useTcmOAuthPopup and provide exchangeCode manually. If you specifically want the older popup-only route-backed behavior, useTcmOAuthPopupRoute remains available as a compatibility API.
Important Constraint
This hook does not make pure browser-only apps fully supported. Popup or redirect can run in the browser, but token exchange still belongs on your server because Portal.Service currently requires client_secret.