Getting Started
React SDK

React SDK

camel-accounts-react is a drop-in popup login widget: a styled button, a context provider that stores tokens, and a hook for reading the user. It handles PKCE, state validation, and the code exchange for you.

npm install camel-accounts-react

How it works

  1. login() generates a PKCE pair and opens a popup to /oauth/authorize
  2. The user signs in and consents inside the popup (Camel Accounts' own UI)
  3. The popup lands on /widget-callback on the issuer and postMessages the authorization code back to your window
  4. The SDK exchanges the code at /oauth/token and closes the popup
  5. Tokens + userinfo are available via useCamelAuth()

Because the callback is hosted on the issuer itself (https://accounts.camelcreatives.com/widget-callback), your app doesn't need its own callback route.

1. Register the client

Your client must include the widget callback in its registered redirect URIs:

https://accounts.camelcreatives.com/widget-callback

Add it via the Developer Console (or API) alongside any other URIs you use:

{
  "redirect_uris": [
    "https://yourapp.com/callback",
    "https://accounts.camelcreatives.com/widget-callback"
  ],
  "allowed_scopes": ["openid", "profile", "email"]
}

2. Wrap your app

The provider takes a single config object:

import { CamelAuthProvider } from "camel-accounts-react";
import "camel-accounts-react/style.css";
 
function App() {
  return (
    <CamelAuthProvider
      config={{
        issuer: "https://accounts.camelcreatives.com",
        clientId: "your-app-web",
        scopes: ["openid", "profile", "email"],
      }}
    >
      <YourRoutes />
    </CamelAuthProvider>
  );
}

Config reference

PropTypeDefaultDescription
issuerstring(required)Camel Accounts base URL
clientIdstring(required)Your registered client_id
scopesstring[]["openid", "profile", "email"]OAuth scopes to request
redirectPathstring"/widget-callback"Path on the issuer used as the popup callback
storage"memory" | "localStorage""memory"Where tokens persist

Storage modes

  • "memory" (default) — tokens live in React state only; a page refresh signs the user out. Best when your own backend session is the real session.
  • "localStorage" — tokens survive refreshes under camel_auth_tokens. Only use this if the browser is fully trusted with the tokens; prefer memory + your own httpOnly-cookie session where possible.

3. Add the button and read state

import { CamelLoginButton, useCamelAuth } from "camel-accounts-react";
 
function LoginSection() {
  const { user, tokens, authenticated, loading, login, logout, getAccessToken } =
    useCamelAuth();
 
  if (loading) return <span>Loading…</span>;
 
  if (authenticated) {
    return (
      <div>
        <span>Signed in as {user?.name ?? user?.email ?? user?.sub}</span>
        <button onClick={logout}>Sign out</button>
      </div>
    );
  }
 
  return <CamelLoginButton onClick={login} />;
}

useCamelAuth() returns

PropertyTypeDescription
userCamelAuthUser | nullClaims from /oauth/userinfo
tokensCamelAuthTokens | null{ accessToken, refreshToken, expiresIn, scope }
authenticatedbooleanTrue while an access token exists
loadingbooleanInitial token restoration in progress
login() => voidOpens the popup flow
logout() => voidClears tokens + user state locally
getAccessToken() => string | nullCurrent access token for calling APIs

Types

interface CamelAuthUser {
  sub: string;
  name?: string;
  email?: string;
  email_verified?: boolean;
  phone_number?: string;
  phone_number_verified?: boolean;
  picture?: string;
}
 
interface CamelAuthTokens {
  accessToken: string;
  refreshToken: string;
  expiresIn: number;
  scope: string;
}

<CamelLoginButton> props

PropTypeDefault
onClick() => void— (pass login)
disabledbooleanfalse
labelstring"Sign in with Camel Accounts"
logostring— (built-in camel mark)

Pass logo to show your own mark on the left (Google-style), e.g. <CamelLoginButton onClick={login} logo="/logo.jpeg" />.

Styling: import camel-accounts-react/style.css for the default look; the button uses BEM class .camel-login-btn, so you can override it freely.

Calling your own backend

Pass the access token as a bearer token; verify it server-side as described in Backend Token Verification:

const res = await fetch("/api/orders", {
  headers: { Authorization: `Bearer ${getAccessToken()}` },
});
if (res.status === 401) {
  // access token expired (15 min TTL) — exchange the refresh token,
  // or simply have the user click Sign in again
}

Heads-up: the SDK does not auto-refresh. Access tokens live 15 minutes; either call /oauth/token with grant_type=refresh_token yourself when a 401 arrives, or treat the widget as a short-lived identity assertion in front of your own cookie session.

Popup notes

  • The popup is 500×600 and centered; browsers block popups not triggered by a direct user gesture — always call login() from an event handler.
  • logout() only clears local state. To end the Camel Accounts browser session itself, send the user to the Cockpit and sign out there.