@meshagent/meshagent-react-auth
v0.40.2
Published
Meshagent React Auth Helpers
Readme
Meshagent React Auth
React helpers for browser OAuth login against Meshagent.
This package sits on top of @meshagent/meshagent-ts-auth and gives you React-friendly hooks for:
- starting a PKCE OAuth redirect
- exchanging the callback
codefor tokens - refreshing access tokens before protected requests
- loading the current user profile into auth state
- subscribing to auth state from React components
It is designed for browser React apps and does not require React Query or a provider wrapper.
Install
npm install @meshagent/meshagent-react-authIf your app also imports lower-level auth primitives or the core Meshagent client directly, add those as direct dependencies too:
npm install @meshagent/meshagent-ts-auth @meshagent/meshagentBefore You Get Started
Create an OAuth client in Meshagent Studio and register your callback URL.
- Sign in to https://studio.meshagent.com.
- Select your project
- Open "OAuth Clients" at the bottom of the left menu
- Click "New OAuth Client" button at the top
- Add
- name for the client id (e.g. "My App")
- enter "email" for the scope
- add redirect URIs (e.g. "http://localhost:3000/")
- Upon successful creation, you will see the client id and client secret. Click "Copy" button to copy the client id and client secret to clipboard. You will need them later when you run the app.
You will need these values throughout the examples:
oauthClientId: the OAuth client ID from Meshagent StudiocallbackUrl: the URL Meshagent redirects back to after login - this must match the redirect URI you registered in Studio
Optional
serverUrl: your Meshagent API base URL, useshttps://api.meshagent.comas default
What This Package Exports
useAuth: main hook for login, callback handling, session refresh, and current-user loadinguseLoginScope: compatibility alias for the older signed-in hook APIuseEnsureLogin: compatibility alias for the older same-page login APIuseMAuthResponse: callback hook that exchanges the OAuth authorization codeuseMeshagentAuth: React subscription hook for auth statebuildOAuthAuthorizeUrl: manual helper for custom login launches
Typical Flow
- Render your app normally. No auth provider wrapper is required.
- For the simplest same-page flow, run
useAuth(...)and read auth state withuseMeshagentAuth(). - If you prefer a dedicated callback route, render
useMAuthResponse(...)on that route and protect the rest of the app withuseAuth(...). - Read live auth state anywhere with
useMeshagentAuth().
useAuth(...) defaults autoSignIn to true, so it will immediately launch the OAuth redirect when there is no session yet. Set autoSignIn: false when you want to show your own "Sign in" button.
Quick Start
Simplest Flow: useAuth(...)
Use useAuth(...) when you want the same component to handle both the initial login redirect and the callback return.
If you omit callbackUrl, it uses the current page as the callback URL and strips the OAuth query params after a successful return.
import {
useAuth,
useMeshagentAuth,
} from "@meshagent/meshagent-react-auth";
const oauthClientId = "YOUR_OAUTH_CLIENT_ID";
export function App(): JSX.Element {
const { failed, refreshing, refresh } = useAuth({
oauthClientId,
});
const auth = useMeshagentAuth();
if (refreshing) {
return <p>Signing you in...</p>;
}
if (failed) {
return (
<div>
<p>Authentication failed: {String(failed)}</p>
<button onClick={refresh}>Retry</button>
</div>
);
}
return <pre>{JSON.stringify(auth, null, 2)}</pre>;
}useAuth(...) uses the default shared meshagentAuth store by default, but it also accepts custom auth and storage instances when you need them. useEnsureLogin(...) remains available as a compatibility alias for this same-page flow.
1. Handle The OAuth Callback
Use useMAuthResponse(...) on the route that matches your registered callback URL.
If you do not pass authorizationCode, the hook reads ?code=... from window.location.
import { useEffect } from "react";
import { useMAuthResponse } from "@meshagent/meshagent-react-auth";
// callbackUrl must match redirect URI registered in Studio, e.g. "http://localhost:3000/auth/callback"
const callbackUrl = new URL("/auth/callback", window.location.origin);
const oauthClientId = "YOUR_OAUTH_CLIENT_ID";
export function AuthCallbackPage(): JSX.Element {
const { status, error } = useMAuthResponse({
callbackUrl,
oauthClientId,
});
useEffect(() => {
if (status === "success") {
window.location.replace("/");
}
}, [status]);
if (status === "idle") {
return <p>Missing authorization code.</p>;
}
if (status === "loading") {
return <p>Signing you in...</p>;
}
if (status === "error") {
return <p>Authentication failed: {error}</p>;
}
return <p>Login complete. Redirecting...</p>;
}After a successful exchange, the hook stores the access token, refresh token, expiration, and current user in the underlying auth store.
2. Protect The Signed-In Part Of Your App
Use useAuth(...) anywhere you want to ensure that:
- the user has a session
- the access token is still valid enough
- the current user profile has been loaded into auth state
The example below disables auto-redirect so the UI can show manual sign-in buttons.
import {
useAuth,
useMeshagentAuth,
} from "@meshagent/meshagent-react-auth";
import { meshagentAuth } from "@meshagent/meshagent-ts-auth";
const callbackUrl = new URL("/auth/callback", window.location.origin);
const oauthClientId = "YOUR_OAUTH_CLIENT_ID";
export function ProtectedApp(): JSX.Element {
const {
failed,
isSigningIn,
refreshing,
signIn,
refresh,
user,
} = useAuth({
callbackUrl,
oauthClientId,
scope: "email",
autoSignIn: false,
});
if (refreshing) {
return <p>Checking session...</p>;
}
if (!user) {
return (
<div>
{failed ? <p>Authentication failed: {String(failed)}</p> : null}
<button onClick={() => void signIn()} disabled={isSigningIn}>
Sign in
</button>
<button onClick={() => void signIn("google")} disabled={isSigningIn}>
Continue with Google
</button>
<button onClick={refresh} disabled={isSigningIn}>
Retry
</button>
</div>
);
}
return <AuthenticatedHome />;
}
function AuthenticatedHome(): JSX.Element {
const auth = useMeshagentAuth();
return (
<div>
<p>Signed in.</p>
<pre>{JSON.stringify(auth, null, 2)}</pre>
<button onClick={() => meshagentAuth.signOut()}>Sign out</button>
</div>
);
}If you want automatic redirect instead of a sign-in screen, omit autoSignIn:
const auth = useAuth({ callbackUrl, oauthClientId });When there is no session, that hook will immediately start the OAuth redirect flow.
3. Read Auth State Anywhere
useMeshagentAuth() is the smallest hook in the package. It subscribes to the underlying auth store and returns the current snapshot:
import { useMeshagentAuth } from "@meshagent/meshagent-react-auth";
export function SessionDebugPanel(): JSX.Element {
const auth = useMeshagentAuth();
return <pre>{JSON.stringify(auth, null, 2)}</pre>;
}The returned snapshot has this shape:
{
accessToken: string | null;
refreshToken: string | null;
expiration: Date | null;
user: Record<string, unknown> | null;
}user is intentionally application-specific. Model it in your app instead of assuming fixed fields in shared code.
Example: Manual Authorize URL
Use buildOAuthAuthorizeUrl(...) when you want manual control over when and how the browser is redirected.
This helper also saves the PKCE verifier so that useMAuthResponse(...) can complete the callback exchange later.
import { buildOAuthAuthorizeUrl } from "@meshagent/meshagent-react-auth";
const serverUrl = "https://api.meshagent.com";
const callbackUrl = new URL("/auth/callback", window.location.origin);
const oauthClientId = "YOUR_OAUTH_CLIENT_ID";
export async function signInWithGoogle(): Promise<void> {
const authorizeUrl = await buildOAuthAuthorizeUrl({
serverUrl,
callbackUrl,
oauthClientId,
scope: "email",
provider: "google",
extraQueryParams: {
invitation: "abc123",
},
});
window.location.assign(authorizeUrl.toString());
}If you pass custom auth or storage, use the same instances in both the login-launch side and the callback side.
Passing storage alone changes PKCE verifier storage. Session persistence follows the auth instance you use.
API Reference
useAuth(options)
Primary auth hook for browser login flows.
What it does:
- launches the browser OAuth redirect when there is no session yet
- exchanges the callback
codewhen the current URL matches the callback URL - loads the current user into auth state
- refreshes the access token when needed before protected requests
- signs out automatically if token refresh fails
- signs out automatically if profile loading returns
401or403 - strips OAuth query params from the current URL after a successful callback exchange
- dedupes duplicate effect runs for the same login attempt
Important options:
oauthClientId: required OAuth client IDserverUrl: optional Meshagent base URL, defaults tohttps://api.meshagent.comcallbackUrl: optional callback URL, defaults to the current pagescope: optional OAuth scope, defaults to"profile"provider: optional provider slug to pass through to/oauth/authorizeextraQueryParams: optional extra query params for/oauth/authorizestorage: optional custom storage for PKCE verifier cachingauth: optional customMeshagentAuthinstanceautoSignIn: optional, defaults totrue
Returned fields:
| Field | Meaning |
| --- | --- |
| failed | Most recent error, or null |
| isCancelled | Currently always false in this browser redirect implementation |
| isSigningIn | true while a sign-in launch is in progress |
| refreshing | true while callback exchange, session validation, or profile loading is running |
| user | Current user from auth state, or null |
| signIn(provider?) | Starts the OAuth redirect, optionally forcing a provider |
| refresh() | Re-runs the auth flow |
| isLoginLaunched | Useful for deciding when to show login or retry UI |
useAuth(...) replaces the overlap between useEnsureLogin(...) and useLoginScope(...). Both legacy names still exist as wrappers for compatibility.
Legacy Aliases
useEnsureLogin(options) is a compatibility wrapper over useAuth(...) for the old same-page login API. It still returns:
| Field | Meaning |
| --- | --- |
| status | "loading", "success", or "error" |
| error | Error message string, or null |
| refresh() | Re-runs the auth flow |
useLoginScope(options) is a compatibility wrapper over useAuth(...) for the older signed-in hook API. It returns the same fields as useAuth(...), while keeping callbackUrl required and preserving its previous default scope behavior.
useMAuthResponse(props)
Hook for your OAuth callback route.
What it does:
- reads the authorization code from
authorizationCodeor the current URL - exchanges the code at
/oauth/token - stores access token, refresh token, and expiration in auth state
- loads the current user profile
- stores that user in auth state
It does not navigate away after success. Redirect to the rest of your app yourself.
If you used custom storage for the PKCE verifier during login launch, pass that same storage here.
Return value:
| status | Meaning |
| --- | --- |
| "idle" | No authorization code was found |
| "loading" | Token exchange is in progress |
| "success" | Exchange and profile load completed |
| "error" | Exchange failed |
The returned error is the message string from the failed query, or null.
useMeshagentAuth(auth?)
Subscribes to a MeshagentAuth store with useSyncExternalStore and returns the current snapshot.
Use this anywhere you want React components to update when tokens, expiration, or user state changes.
buildOAuthAuthorizeUrl(params)
Builds the /oauth/authorize URL and stores a PKCE verifier before redirect.
Supported parameters:
serverUrlcallbackUrloauthClientIdscopeproviderextraQueryParamsstorage
Use this helper when the default signIn() behavior is too opinionated and you need manual redirect control.
storage here controls where the PKCE verifier is cached before the redirect.
Notes
- This package is for browser redirect-based OAuth flows.
useAuth(...)and its legacy aliases will throw if they try to launch login outside a browser environment. - No provider wrapper is required.
useAuth(...),useEnsureLogin(...),useLoginScope(...), anduseMAuthResponse(...)manage their own async state. useMAuthResponse(...)does not clear thecodequery parameter or navigate after success. Most apps should redirect away from the callback page afterstatus === "success".- Sign-out functionality lives in
@meshagent/meshagent-ts-auth, for examplemeshagentAuth.signOut(). - If you need the low-level primitives directly, see
@meshagent/meshagent-ts-auth. This package is the React layer on top of it.
