npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@brunorppaixao/authxao-client

v0.1.2

Published

Standalone browser and React client SDK for authxao.

Downloads

38

Readme

authxao-client

Standalone browser and React consumer SDK for authxao.

This package targets the current public authxao provider contract:

  • login and register send appId in the request body
  • a valid existing global authxao account is auto-attached to a new appId on the first successful password login for that app
  • refresh and logout depend on the provider's HTTP-only cookie
  • access tokens stay in memory
  • refresh rotation is family-based, and replaying an already-rotated refresh token forces a full sign-out
  • app-scoped login/register now return app-bound access tokens
  • password login can now return an MFA challenge instead of tokens when TOTP is enabled
  • app-scoped login/register/passkey/OAuth can now also return emailVerificationRequired when the app policy blocks session issuance until the account email is verified
  • /api/auth/me uses appId=<uuid> only
  • /api/auth/context provides one-call app-scoped introspection
  • /api/auth/introspect is the canonical backend validation + context endpoint
  • browser consumers do not need to know whether access tokens are HS256 or asymmetric; backend services should validate through /api/auth/introspect or the provider JWKS endpoint
  • /api/auth/policy and /api/auth/capabilities are the current policy-discovery contract for adaptive consumer UI
  • those policy-discovery responses now also include globalRestrictions, which let consumer apps hide auth options that are temporarily disabled platform-wide during incident mode
  • progression award skips are returned as structured non-fatal results
  • the latest operational-confidence work adds backend-only e2e coverage for OAuth conflict/linking, placeholder-account login, worker leasing, and signing-key compromise handling without changing the consumer API surface
  • the admin web app now also includes an authenticated in-app platform reference backed by GET /api/admin/docs/manifest; this is operator-facing documentation and does not change the consumer package contract

Install

npm install @brunorppaixao/authxao-client react react-dom

Minimum required runtime configuration:

  • AUTH_SERVER_URL
  • AUTH_APP_ID

Optional app-API helper configuration:

  • VITE_API_URL / apiBaseUrl is only needed when you want the SDK to also create the authenticated apiFetch helper for your own backend or app API
  • if you only need authxao client methods plus the React provider, omit apiBaseUrl

Recommended React setup:

import { createAuthxaoConsumerApp } from "@brunorppaixao/authxao-client";
import { AuthGate, AuthModal, AuthProviderSettings, useAuthxao } from "@brunorppaixao/authxao-client";

const { client, apiFetch, Provider } = createAuthxaoConsumerApp({
  baseUrl: import.meta.env.VITE_AUTH_SERVER_URL,
  appId: import.meta.env.VITE_AUTH_APP_ID,
  apiBaseUrl: import.meta.env.VITE_API_URL,
  fetch: window.fetch.bind(window)
});

function Dashboard() {
  const { user, appContext, logout } = useAuthxao();
  return (
    <>
      <h1>{user?.name ?? user?.email}</h1>
      <p>{appContext?.app.name}</p>
      <button onClick={() => void logout()}>Sign out</button>
      <AuthProviderSettings />
    </>
  );
}

export function App() {
  return (
    <Provider>
      <AuthGate fallback={<AuthModal initialView="login" />}>
        <Dashboard />
      </AuthGate>
    </Provider>
  );
}

Minimal React setup without the app-API fetch helper:

const { client, Provider } = createAuthxaoConsumerApp({
  baseUrl: import.meta.env.VITE_AUTH_SERVER_URL,
  appId: import.meta.env.VITE_AUTH_APP_ID,
  fetch: window.fetch.bind(window)
});

If you do not want the scaffold helper, the lower-level setup remains available through createAuthxaoClient(...), createAuthenticatedFetch(...), and AuthxaoProvider.

Fastest path

Use the published package if you are integrating from another project.

A copy-friendly example integration is included under:

  • examples/vite-auth-shell.tsx

That example shows the default stack together:

  • createAuthxaoConsumerApp(...)
  • AuthGate
  • AuthModal
  • AuthProviderSettings
  • provider-owned appContext
  • authenticated API fetch wiring

Operational note:

  • if a user already has a valid global authxao account, their first successful password sign-in to a new consumer appId attaches that account to the app automatically

Local package development

The consumer package now has its own package-local TypeScript toolchain and build output.

From the package root:

  • npm install
  • npm run typecheck
  • npm run build
  • npm run pack:check
  • npm run test:smoke

The build emits distributable artifacts into dist/, and the package export map now resolves from those built files rather than directly from src/.

npm run test:smoke packs the package, installs the tarball into a temporary React+Vite app, and verifies that root plus subpath imports compile and build successfully.

Peer dependencies

The package expects the consuming app to provide:

  • react
  • react-dom

The package repository keeps local dev dependencies for these as part of the standalone smoke test and CI path, but consumer applications should still install them explicitly.

Package surfaces

The public package now has explicit layers:

  • @brunorppaixao/authxao-client/core
    • config helpers
    • typed contracts
    • AuthxaoRequestError
    • fetch and role helpers
  • @brunorppaixao/authxao-client/browser
    • everything in core
    • createAuthxaoClient
    • popup OAuth helpers
  • @brunorppaixao/authxao-client/react
    • AuthxaoProvider
    • createAuthxaoConsumerApp
    • useAuthxao
    • headless hooks
  • @brunorppaixao/authxao-client/ui
    • default consumer-side components only

The source tree is now package-shaped as well:

  • src/core/* for shared config, request errors, pure helper utilities, token, and fetch plumbing
  • src/core/types/* for feature-scoped auth, app, client, error, React, and UI contracts behind the stable types barrel
  • src/client/createClient.ts for client composition
  • src/client/internal/* for client runtime concerns such as in-memory token state and refresh orchestration
  • src/client/modules/* for endpoint families such as auth, account, app, OAuth, and SAML
  • src/react/components/* for shared shell primitives, auth-flow forms, and account-security panels
  • src/react/hooks/* for feature-oriented React helpers grouped by auth, account, and MFA flows
  • src/react/internal/* for provider-side auth session orchestration and pure React state helpers
  • src/webauthn/* for browser WebAuthn helpers
  • legacy top-level files remain as compatibility shims during the refactor

The root export still works for compatibility, but new integrations should prefer the explicit submodules.

Supported subpath imports:

  • @brunorppaixao/authxao-client
  • @brunorppaixao/authxao-client/browser
  • @brunorppaixao/authxao-client/core
  • @brunorppaixao/authxao-client/config
  • @brunorppaixao/authxao-client/http
  • @brunorppaixao/authxao-client/react
  • @brunorppaixao/authxao-client/react/components
  • @brunorppaixao/authxao-client/react/hooks
  • @brunorppaixao/authxao-client/session
  • @brunorppaixao/authxao-client/types
  • @brunorppaixao/authxao-client/ui

Compatibility note:

  • config, http, session, and types remain exported for 0.x compatibility
  • new integrations should prefer browser, core, react, and ui

Browser-only features

These features require a real browser environment and should not be expected to run during SSR:

  • popup OAuth flows
  • WebAuthn / passkey registration and authentication
  • any integration that depends on window.fetch.bind(window) or browser credential APIs

Minimal API

const client = createAuthxaoClient({
  baseUrl: "https://auth.paixao.app",
  appId: "consumer-app-uuid",
  fetch: window.fetch.bind(window)
});

await client.login({ identifier: emailOrUsername, password });
await client.verifyMfa({ ticket, code });
const me = await client.getMe();
const token = client.getAccessToken();
await client.refresh();
await client.logout();

For new integrations, prefer the grouped surface when reading or teaching the SDK:

const result = await client.auth.loginFlow({
  identifier: emailOrUsername,
  password
});

if (result.state === "mfa_required") {
  await client.auth.verifyMfaFlow({ ticket: result.ticket, code });
}

const me = await client.app.getMe();
const context = await client.app.getContext();
const sessions = await client.account.getMySessions();

For React consumers, the shortest path is usually:

const { client, apiFetch, Provider } = createAuthxaoConsumerApp({
  baseUrl: import.meta.env.AUTH_SERVER_URL,
  appId: import.meta.env.AUTH_APP_ID,
  apiBaseUrl: import.meta.env.API_URL,
  fetch: window.fetch.bind(window)
});

apiBaseUrl is optional here as well. Only pass it when you want apiFetch pre-bound to your own app API base URL.

The flat surface remains fully supported for compatibility:

  • client.login(...)
  • client.register(...)
  • client.getAppContext(...)
  • client.getMySessions(...)

Flow helpers and guards exist so consumer apps do not need to keep re-implementing ad hoc response branching:

  • client.auth.loginFlow(...)
  • client.auth.registerFlow(...)
  • client.auth.verifyMfaFlow(...)
  • client.auth.authenticateWithPasskeyFlow(...)
  • client.oauth.loginPopupFlow(...)
  • client.oauth.linkPopupFlow(...)
  • isAuthxaoMfaChallengeResponse(...)
  • isAuthxaoEmailVerificationRequiredResponse(...)
  • isAuthxaoAuthResponse(...)

Available methods:

  • login
  • register
  • verifyMfa
  • getPolicy
  • getCapabilities
  • getEmailVerificationStatus
  • sendEmailVerification
  • verifyEmailVerification
  • forgotPassword
  • resetPassword
  • listMfaMethods
  • startTotpEnrollment
  • confirmTotpEnrollment
  • deleteMfaMethod
  • listTrustedDevices
  • deleteTrustedDevice
  • listPasskeys
  • startPasskeyRegistration
  • finishPasskeyRegistration
  • deletePasskey
  • startPasskeyAuthentication
  • finishPasskeyAuthentication
  • registerPasskey
  • authenticateWithPasskey
  • refresh
  • logout
  • verify
  • introspect
  • getMe
  • getAppContext
  • getOAuthStartUrl
  • startOAuthPopup
  • getSamlStartUrl
  • startSamlRedirect
  • getSamlMetadataUrl
  • getSamlMetadata
  • finishSamlCallback
  • getMyIdentities
  • getMyIdentityCapabilities
  • updateProfileImage
  • getAccountLockdownStatus
  • startAccountLockdown
  • liftAccountLockdown
  • getMySessions
  • revokeSession
  • revokeOtherSessions
  • renameSessionDevice
  • getRecentAuthStatus
  • startRecentAuth
  • verifyPasswordRecentAuth
  • verifyMfaRecentAuth
  • unlinkIdentity
  • getMySecurityEvents
  • getProgression
  • awardProgression
  • listAppUsers
  • listAppAuditEntries
  • listAppRoles
  • createAppRole
  • updateAppRole
  • deleteAppRole
  • getAccessToken
  • getValidAccessToken

Helpers:

  • createAuthxaoConsumerApp
  • createAuthenticatedFetch
  • hasRole
  • hasAnyRole
  • isAuthxaoAuthResponse
  • isAuthxaoMfaChallengeResponse
  • isAuthxaoEmailVerificationRequiredResponse
  • isBestEffortProgressionError
  • AuthxaoRequestError with stable status, code, and payload
  • useAuthxaoLoginForm
  • useAuthxaoRegisterForm
  • useAuthxaoConsumerApp
  • useAuthxaoAppContext
  • useAuthxaoEmailVerification
  • useAuthxaoForgotPasswordForm
  • useAuthxaoResetPasswordForm
  • useAuthxaoSocialLogin
  • useAuthxaoSessions
  • useAuthxaoSecurityEvents
  • useAuthxaoRecentAuth
  • useAuthxaoStepUp
  • LoginForm
  • RegisterForm
  • ForgotPasswordForm
  • ResetPasswordForm
  • VerifyEmailNotice
  • SocialLoginButtons
  • AuthGate
  • AuthModal
  • AuthProviderSettings
  • StepUpPanel

React usage

import { createAuthxaoConsumerApp, useAuthxao, useAuthxaoConsumerApp } from "@brunorppaixao/authxao-client";

const { Provider } = createAuthxaoConsumerApp({
  baseUrl: import.meta.env.AUTH_SERVER_URL,
  appId: import.meta.env.AUTH_APP_ID,
  apiBaseUrl: import.meta.env.API_URL,
  fetch: window.fetch.bind(window)
});

function App() {
  return (
    <Provider>
      <Routes />
    </Provider>
  );
}

function ProfileGate() {
  const { user, appContext, login, logout, isAuthenticated } = useAuthxao();
  const { policy, capabilities, reload } = useAuthxaoConsumerApp();
  return null;
}

If you do not need apiFetch, you can omit apiBaseUrl entirely and use const { Provider, client } = createAuthxaoConsumerApp(...).

The provider bootstraps by:

  1. calling refresh
  2. loading scoped /api/auth/me
  3. loading app-scoped /api/auth/context by default
  4. keeping the access token only in memory

If a consumer truly does not want provider-owned app-context hydration, it can opt out:

<AuthxaoProvider client={client} hydrateAppContext={false}>
  <App />
</AuthxaoProvider>

If refresh fails because the provider revoked the refresh-token family after reuse detection, the consumer should clear in-memory auth state and return to an unauthenticated flow instead of retrying.

Current MFA behavior:

  • client.login() may return { mfaRequired: true, ticket, methods }
  • client.login() may also return { emailVerificationRequired: true, code: "APP_EMAIL_VERIFICATION_REQUIRED", email, canResendAt }
  • high-volume auth abuse blocks now surface as AuthxaoRequestError with status === 429 and code === "ABUSE_PROTECTION_TRIGGERED"; consumer UIs should render a generic retry-later message instead of trying to distinguish identifier-specific causes
  • TOTP-protected password login may now return { mfaRequired: true, ticket, methods, risk? }; the optional risk object is informational and should only be used for generic copy such as “extra verification required on this device”
  • client.verify() and client.introspect() now return an assurance object containing amr, aal, and authTime when the provider issued a current auth session token
  • client.verifyMfa() completes the normal login flow and stores the returned access token
  • session lists can now surface risk.level === "elevated" with anomaly-derived signals such as fan-out or auth-method change; consumer UIs should treat that as a stronger review signal, not as a separate session state machine
  • getPolicy() and getCapabilities() should now be treated as the source of truth for both app policy and any global kill-switch overrides affecting registration, provider login, linking, or passkey enrollment
  • getMySecurityEvents() now accepts type and requestId filters in addition to category/severity/time bounds when a consumer account-security screen needs tighter forensic filtering
  • client.getAccountSafety() and useAuthxaoAccountSafety() now expose the backend account posture contract for security recommendation screens
  • client.getEmailChangeStatus(), client.startEmailChange(), client.cancelEmailChange(), and client.confirmEmailChange() now expose the secure email-change lifecycle
  • useAuthxaoEmailChange() and EmailChangePanel provide a default consumer-side flow for recent-auth-gated email changes without hosted pages
  • client.checkUsernameAvailability(), client.getUsernameStatus(), client.changeUsername(), and useAuthxaoUsername() now expose the hardened username lifecycle
  • current-user and capability responses may include placeholderEmail, which consumers should treat as an upgrade-needed signal rather than a deliverable recovery address
  • getPolicy() and getCapabilities() may now include policyTemplate and conditionalRules, which lets consumer UI explain inherited app policy and role-targeted restrictions without hardcoding template metadata
  • client.evaluateAuthorization({ appId?, action, capability?, resourceType?, resourceId? }) now exposes the backend app-role/capability evaluation helper for consumer backends or trusted in-app management screens
  • the current operational-confidence test work does not change the consumer runtime API; it adds backend HTTP-level e2e coverage so the existing consumer-facing contracts are exercised against a real server and dedicated test database
  • recent-auth, email-change, and lockdown flows are now part of that backend e2e coverage, which lowers regression risk for existing consumer-side hooks and default account-security components without changing their public API
  • the new webhook/maintenance worker model is backend/operator only; consumer-side runtime behavior and package APIs remain unchanged for this slice
  • signing-key lifecycle and JWKS-rotation operations are also backend/operator concerns; consumer-side browser integrations still consume the same access-token flow and do not need new package code for this slice
  • webhook delivery is an operator-only backend concern; browser consumers do not need new client code for this slice and should keep treating security-event visibility as read-only account history unless the product explicitly adds operator tooling
  • readiness and retention cleanup are also provider/operator concerns; the consumer package remains unchanged for this slice and should continue relying on normal auth/session endpoints rather than health/maintenance APIs
  • client.verifyMfa({ ..., rememberDevice: true }) can remember the current browser as a trusted device
  • TOTP enrollment returns an otpauthUrl and one-time recovery codes
  • client.regenerateRecoveryCodes({ code? , recoveryCode? }) rotates the recovery-code set after proving a current MFA factor
  • default reusable MFA UI is also available through:
    • MfaChallengeForm
    • TotpEnrollmentPanel
    • useAuthxaoMfaChallengeForm
    • useAuthxaoTotpEnrollment
  • AuthModal can now transition from login into the MFA challenge view automatically when client.login() returns an MFA ticket
  • AuthProviderSettings now includes trusted-device visibility/revocation, provider-linking actions, and recovery-code rotation

The grouped auth helpers expose the same behavior with a discriminated result:

  • client.auth.loginFlow(...) returns authenticated, mfa_required, or email_verification_required
  • client.auth.registerFlow(...) returns authenticated or email_verification_required
  • client.auth.verifyMfaFlow(...) returns authenticated or email_verification_required
  • client.oauth.loginPopupFlow(...) returns authenticated or email_verification_required

Current passkey behavior:

  • client.registerPasskey({ name? }) performs passkey enrollment end to end in supported browsers
  • client.authenticateWithPasskey({ appId? }) performs passkey sign-in end to end and stores the returned access token
  • client.auth.registerPasskeyFlow({ name? }) returns { state: "registered", passkey }
  • client.auth.authenticateWithPasskeyFlow({ appId? }) returns authenticated or email_verification_required
  • lower-level WebAuthn steps are also available if a consumer needs custom UI:
    • startPasskeyRegistration
    • finishPasskeyRegistration
    • startPasskeyAuthentication
    • finishPasskeyAuthentication
  • LoginForm now includes a passkey sign-in button when WebAuthn is available
  • AuthProviderSettings now includes passkey enrollment, listing, and removal
  • passkey sign-in can also return emailVerificationRequired when the app policy requires verified email before issuing app access

Policy-aware consumer behavior

The current recommendation is:

  • load client.getPolicy() or client.getCapabilities() before rendering auth UI with strong app-specific requirements
  • hide registration when allowRegistration === false
  • hide Google/Apple actions when the provider is not enabled or not configured
  • hide passkey enrollment when allowPasskeyRegistration === false
  • surface a verification prompt when login/register returns emailVerificationRequired

getCapabilities() also returns current-user auth-method summary when authenticated:

  • verified email state
  • linked providers
  • passkey presence
  • MFA presence
  • trusted-device presence
  • recent-auth status

This keeps consumer apps policy-driven instead of hardcoding assumptions.

Consumer-app recommendation:

  • if the configured authxao app enables registration, MFA management, passkeys, linked providers, email verification, account recovery, or recent-auth security actions, the consumer app should surface those capabilities or intentionally omit them as a product decision
  • missing capability exposure should not come from SDK discoverability problems; prefer the grouped client surface and reusable account/auth components before building custom wrappers

For account-security UX:

  • getMyIdentityCapabilities() now returns sign-in and recovery-safety summary fields
  • unlinking a provider or removing a passkey can be blocked when the remaining account state would be only an unverified password path
  • recent-auth failures are exposed through AuthxaoRequestError.code === "RECENT_AUTH_REQUIRED"
  • popup OAuth login conflicts are exposed through AuthxaoOAuthPopupError.code === "account_link_requires_authenticated_session"
  • popup OAuth login failures that require email verification now preserve email, appId, and canResendAt on the thrown AuthxaoOAuthPopupError
  • consumer apps can now start tenant SAML login flows through client.getSamlStartUrl(slug, options?) or client.startSamlRedirect(slug, options?)
  • tenant SAML metadata and manual callback completion are also available through client.getSamlMetadataUrl(slug), client.getSamlMetadata(slug), and client.finishSamlCallback(slug, { samlResponse, relayState })
  • StepUpPanel and useAuthxaoStepUp() provide a reusable consumer-side recent-auth flow for sensitive actions

Reusable auth UI

The package now includes a first reusable auth UI layer on top of the headless client/context.

Headless hooks:

  • useAuthxaoConsumerApp()
  • useAuthxaoLoginForm()
  • useAuthxaoRegisterForm()
  • useAuthxaoAppContext()
  • useAuthxaoEmailVerification()
  • useAuthxaoForgotPasswordForm()
  • useAuthxaoResetPasswordForm()
  • useAuthxaoSocialLogin("google")
  • useAuthxaoSessions()
  • useAuthxaoSecurityEvents()
  • useAuthxaoRecentAuth()

Default components:

  • LoginForm
  • RegisterForm
  • ForgotPasswordForm
  • ResetPasswordForm
  • SocialLoginButtons
  • AuthGate
  • AuthSurface
  • AuthModal
  • AuthProviderSettings
  • VerifyEmailNotice

Example:

import {
  AuthGate,
  createAuthxaoConsumerApp,
  LoginForm,
  RegisterForm
} from "@brunorppaixao/authxao-client";

const { Provider } = createAuthxaoConsumerApp({
  baseUrl: import.meta.env.AUTH_SERVER_URL,
  appId: import.meta.env.AUTH_APP_ID,
  fetch: window.fetch.bind(window)
});

function AuthenticationArea() {
  return (
    <Provider>
      <AuthGate fallback={<LoginForm forgotPasswordHref="/forgot-password" />}>
        <RegisterForm />
      </AuthGate>
    </Provider>
  );
}

These defaults are intentionally compact and copy-friendly:

  • business logic stays in the shared client/context
  • apps can use the headless hooks and replace the visuals entirely
  • apps can also use the default components directly for consistent auth UX
  • every reusable component also accepts a theme prop for shell/panel/input/button/message/chip styling overrides

Password recovery is also exposed through the same package:

  • client.forgotPassword({ email })
  • client.resetPassword({ token, newPassword })
  • ForgotPasswordForm
  • ResetPasswordForm

Account-management UI is now included too:

  • AuthProviderSettings
    • loads linked identities from /api/auth/identities
    • loads recent security events from /api/auth/security-events
    • supports unlinking non-password identities
    • supports passkey enrollment and removal

There is also a higher-level AuthModal component that switches between login, register, and forgot-password views while keeping the same underlying authxao client/context.

Popup failures are now structured. startOAuthPopup() throws AuthxaoOAuthPopupError, including provider and optional code.

Recent security events now include refresh-token reuse detection and family revocation in addition to login, logout, and password lifecycle events.

Current explicit Google conflict code:

  • identity_already_linked

Other explicit OAuth popup/config codes now include:

  • provider_not_configured

Local package validation:

cd /home/bruno/Projects/authxao-client
npm run typecheck

Request rules that matter

  • Login/register body:
{ "identifier": "[email protected]", "password": "secret123", "appId": "app-uuid" }

identifier can be either the user email or the canonical username.

  • Current user:

    • GET /api/auth/me?appId=<uuid>
  • App context/introspection:

    • GET /api/auth/context?appId=<uuid>
  • Backend introspection:

    • GET /api/auth/introspect
    • optional ?appId=<uuid> when the token is not already app-bound
  • App users / leaderboard:

    • GET /api/auth/apps/users?appId=<uuid>&sort=experience&order=desc
  • Refresh:

    • POST /api/auth/refresh
    • requires credentials: "include"
  • Logout:

    • POST /api/auth/logout
    • requires credentials: "include"

Progression awarding

Call awardProgression({ action }) only after the business action succeeds.

Treat these provider responses as non-fatal best-effort misses:

  • { "action": "...", "awarded": false, "reason": "no_active_session" }
  • { "action": "...", "awarded": false, "reason": "rule_not_found" }

Example:

const result = await client.awardProgression({ action: "create_word" });

if (result.awarded) {
  console.log(result.progression.level);
}

Consumer-managed roles

The provider now exposes authenticated app-role management for users with app-scoped Owner or Administrator.

Example:

await client.createAppRole({
  name: "Editor",
  description: "Can manage content",
  capabilities: ["content.manage", "content.publish"]
});

const roles = await client.listAppRoles();
await client.updateAppRole({
  roleId: roles.roles[0].id,
  description: "Updated description",
  capabilities: ["content.manage", "content.publish", "content.archive"]
});
await client.deleteAppRole(roles.roles[0].id);

Default roles are protected:

  • Administrator
  • Moderator
  • Owner
  • User

They can be described, but not deleted, and their names cannot be changed.

Custom roles may also include explicit capability strings, so app authorization can evolve without hardcoding every permission to a role name.

Returned role shape:

type AuthxaoAppRole = {
  id: string;
  appId: string;
  name: string;
  description?: string | null;
  capabilities: string[];
};

Guideline:

  • use role names for labels, menus, and operator-facing copy
  • use capabilities for backend authorization and feature gating when permissions need to be more specific than role names

Convenience helpers are available for both patterns:

import {
  hasAnyCapability,
  hasAnyRole,
  hasCapability,
  hasRole
} from "@brunorppaixao/authxao-client";

if (hasCapability(appContext, "banana.read")) {
  // render a capability-gated control
}

if (hasAnyCapability(appContext, ["banana.write", "banana.admin"])) {
  // render a higher-privilege control
}

Consumer-managed user settings

Authxao also supports dynamic app-scoped user setting definitions plus per-user values. This keeps app-specific preferences such as exercise_loop out of the provider schema while still allowing them to hydrate through /api/auth/me and /api/auth/context.

Definition management:

await client.createAppUserSetting({
  key: "exercise_loop",
  label: "Exercise Loop",
  description: "Remember whether solved exercises may repeat",
  valueType: "boolean",
  defaultValue: false,
  isUserEditable: true,
  isActive: true
});

const settings = await client.listAppUserSettings();
await client.updateAppUserSetting({
  settingId: settings.settings[0].id,
  label: "Exercise Loop",
  defaultValue: true
});

Current-user values:

await client.updateMySettings({
  settings: {
    exercise_loop: true
  }
});

const { userSettings } = await client.getMySettings();
console.log(userSettings.exercise_loop);

Hydration behavior:

  • client.getMe({ appId }) now exposes merged app-scoped userSettings
  • client.getAppContext(appId) also exposes merged userSettings
  • the React provider keeps that hydrated app context on useAuthxao().appContext

Recommended consumer admin panel

For production consumer apps, it is strongly advised to ship an app administration surface instead of treating these authxao features as hidden backend-only plumbing.

Top-priority app admin capabilities:

  • manage app roles
  • manage explicit capabilities per role
  • manage dynamic app user-setting definitions
  • adjust defaults and editability flags for app settings without redeploying authxao
  • let the signed-in operator inspect and change their own app-scoped settings for debugging and support flows

Current SDK support:

  • role management: listAppRoles, createAppRole, updateAppRole, deleteAppRole
  • user setting definition management: listAppUserSettings, createAppUserSetting, updateAppUserSetting, deleteAppUserSetting
  • current-user setting values: getMySettings, updateMySettings
  • app-scoped hydration: getMe() and getAppContext() both expose merged userSettings

Important boundary:

  • the public consumer SDK is app-scoped and current-user oriented
  • if your product needs broad operator review of other users' settings, build that through your backend or through authxao's provider/admin surface rather than assuming the browser SDK should expose global admin visibility

Practical split:

  • keep account self-service in AuthProviderSettings
  • add a dedicated administrator panel in the consumer app for role schema, capability schema, and app-setting schema management
  • use the authxao provider/admin app for cross-user investigations and platform-wide operator workflows

Account identities and security events

The provider now exposes the first account-management primitives needed for linked-provider UI:

  • GET /api/auth/identities
  • DELETE /api/auth/identities/:identityId
  • GET /api/auth/security-events?limit=25

Current behavior:

  • password login is represented as a PASSWORD identity
  • password identity cannot be unlinked
  • non-password identities can only be unlinked when they are not the last sign-in identity
  • recent security events include login success/failure, session refresh/revoke, and password reset events

OAuth Providers

The consumer package now exposes provider-aware OAuth helpers:

  • getOAuthStartUrl("google" | "apple", ...)
  • startOAuthPopup("google" | "apple", ...)
  • client.oauth.loginPopupFlow("google" | "apple", ...)
  • client.oauth.linkPopupFlow("google" | "apple", ...)

Example:

const result = await client.startOAuthPopup("google", {
  intent: "login"
});

if (result.accessToken) {
  const me = await client.getMe();
}

Linking example for an already authenticated account:

await client.startOAuthPopup("google", {
  intent: "link"
});

SocialLoginButtons also accepts providers and labels, so consumer apps can render Google-only, Apple-only, or mixed-provider entry using the same authxao flow layer.

App context and leaderboards

Use getAppContext() when a consumer backend or frontend wants a single app-scoped trust payload with:

  • app metadata
  • user identity
  • app membership
  • active session presence
  • roles
  • capabilities
  • progression
  • merged user settings
  • role-management capability

Use introspect() when a consumer backend wants one canonical validation path that both verifies the bearer token and resolves app-scoped context.

The app context payload includes:

  • roles
  • capabilities
  • progression
  • userSettings
  • membership
  • session
  • canManageRoles

Use listAppUsers() for app-scoped directories or leaderboards.

Example:

const context = await client.getAppContext();
const leaderboard = await client.listAppUsers({ sort: "experience", order: "desc", limit: 10 });

When using AuthxaoProvider, the same payload is now hydrated into React context by default:

const { appContext } = useAuthxao();
// or:
const { appContext, reload } = useAuthxaoAppContext();

Audit entries for role-definition changes are also available to authorized app managers:

const logs = await client.listAppAuditEntries();