@brunorppaixao/authxao-client
v0.1.2
Published
Standalone browser and React client SDK for authxao.
Downloads
38
Maintainers
Readme
authxao-client
Standalone browser and React consumer SDK for authxao.
This package targets the current public authxao provider contract:
loginandregistersendappIdin the request body- a valid existing global authxao account is auto-attached to a new
appIdon 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
emailVerificationRequiredwhen the app policy blocks session issuance until the account email is verified /api/auth/meusesappId=<uuid>only/api/auth/contextprovides one-call app-scoped introspection/api/auth/introspectis 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/introspector the provider JWKS endpoint /api/auth/policyand/api/auth/capabilitiesare 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-domMinimum required runtime configuration:
AUTH_SERVER_URLAUTH_APP_ID
Optional app-API helper configuration:
VITE_API_URL/apiBaseUrlis only needed when you want the SDK to also create the authenticatedapiFetchhelper 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(...)AuthGateAuthModalAuthProviderSettings- 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
appIdattaches 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 installnpm run typechecknpm run buildnpm run pack:checknpm 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:
reactreact-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
- everything in
@brunorppaixao/authxao-client/reactAuthxaoProvidercreateAuthxaoConsumerAppuseAuthxao- 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 plumbingsrc/core/types/*for feature-scoped auth, app, client, error, React, and UI contracts behind the stabletypesbarrelsrc/client/createClient.tsfor client compositionsrc/client/internal/*for client runtime concerns such as in-memory token state and refresh orchestrationsrc/client/modules/*for endpoint families such as auth, account, app, OAuth, and SAMLsrc/react/components/*for shared shell primitives, auth-flow forms, and account-security panelssrc/react/hooks/*for feature-oriented React helpers grouped by auth, account, and MFA flowssrc/react/internal/*for provider-side auth session orchestration and pure React state helperssrc/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, andtypesremain exported for0.xcompatibility- new integrations should prefer
browser,core,react, andui
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:
loginregisterverifyMfagetPolicygetCapabilitiesgetEmailVerificationStatussendEmailVerificationverifyEmailVerificationforgotPasswordresetPasswordlistMfaMethodsstartTotpEnrollmentconfirmTotpEnrollmentdeleteMfaMethodlistTrustedDevicesdeleteTrustedDevicelistPasskeysstartPasskeyRegistrationfinishPasskeyRegistrationdeletePasskeystartPasskeyAuthenticationfinishPasskeyAuthenticationregisterPasskeyauthenticateWithPasskeyrefreshlogoutverifyintrospectgetMegetAppContextgetOAuthStartUrlstartOAuthPopupgetSamlStartUrlstartSamlRedirectgetSamlMetadataUrlgetSamlMetadatafinishSamlCallbackgetMyIdentitiesgetMyIdentityCapabilitiesupdateProfileImagegetAccountLockdownStatusstartAccountLockdownliftAccountLockdowngetMySessionsrevokeSessionrevokeOtherSessionsrenameSessionDevicegetRecentAuthStatusstartRecentAuthverifyPasswordRecentAuthverifyMfaRecentAuthunlinkIdentitygetMySecurityEventsgetProgressionawardProgressionlistAppUserslistAppAuditEntrieslistAppRolescreateAppRoleupdateAppRoledeleteAppRolegetAccessTokengetValidAccessToken
Helpers:
createAuthxaoConsumerAppcreateAuthenticatedFetchhasRolehasAnyRoleisAuthxaoAuthResponseisAuthxaoMfaChallengeResponseisAuthxaoEmailVerificationRequiredResponseisBestEffortProgressionErrorAuthxaoRequestErrorwith stablestatus,code, andpayloaduseAuthxaoLoginFormuseAuthxaoRegisterFormuseAuthxaoConsumerAppuseAuthxaoAppContextuseAuthxaoEmailVerificationuseAuthxaoForgotPasswordFormuseAuthxaoResetPasswordFormuseAuthxaoSocialLoginuseAuthxaoSessionsuseAuthxaoSecurityEventsuseAuthxaoRecentAuthuseAuthxaoStepUpLoginFormRegisterFormForgotPasswordFormResetPasswordFormVerifyEmailNoticeSocialLoginButtonsAuthGateAuthModalAuthProviderSettingsStepUpPanel
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:
- calling
refresh - loading scoped
/api/auth/me - loading app-scoped
/api/auth/contextby default - 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
AuthxaoRequestErrorwithstatus === 429andcode === "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 optionalriskobject is informational and should only be used for generic copy such as “extra verification required on this device” client.verify()andclient.introspect()now return anassuranceobject containingamr,aal, andauthTimewhen the provider issued a current auth session tokenclient.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()andgetCapabilities()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 enrollmentgetMySecurityEvents()now acceptstypeandrequestIdfilters in addition to category/severity/time bounds when a consumer account-security screen needs tighter forensic filteringclient.getAccountSafety()anduseAuthxaoAccountSafety()now expose the backend account posture contract for security recommendation screensclient.getEmailChangeStatus(),client.startEmailChange(),client.cancelEmailChange(), andclient.confirmEmailChange()now expose the secure email-change lifecycleuseAuthxaoEmailChange()andEmailChangePanelprovide a default consumer-side flow for recent-auth-gated email changes without hosted pagesclient.checkUsernameAvailability(),client.getUsernameStatus(),client.changeUsername(), anduseAuthxaoUsername()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()andgetCapabilities()may now includepolicyTemplateandconditionalRules, which lets consumer UI explain inherited app policy and role-targeted restrictions without hardcoding template metadataclient.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
otpauthUrland 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:
MfaChallengeFormTotpEnrollmentPaneluseAuthxaoMfaChallengeFormuseAuthxaoTotpEnrollment
AuthModalcan now transition from login into the MFA challenge view automatically whenclient.login()returns an MFA ticketAuthProviderSettingsnow 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(...)returnsauthenticated,mfa_required, oremail_verification_requiredclient.auth.registerFlow(...)returnsauthenticatedoremail_verification_requiredclient.auth.verifyMfaFlow(...)returnsauthenticatedoremail_verification_requiredclient.oauth.loginPopupFlow(...)returnsauthenticatedoremail_verification_required
Current passkey behavior:
client.registerPasskey({ name? })performs passkey enrollment end to end in supported browsersclient.authenticateWithPasskey({ appId? })performs passkey sign-in end to end and stores the returned access tokenclient.auth.registerPasskeyFlow({ name? })returns{ state: "registered", passkey }client.auth.authenticateWithPasskeyFlow({ appId? })returnsauthenticatedoremail_verification_required- lower-level WebAuthn steps are also available if a consumer needs custom UI:
startPasskeyRegistrationfinishPasskeyRegistrationstartPasskeyAuthenticationfinishPasskeyAuthentication
LoginFormnow includes a passkey sign-in button when WebAuthn is availableAuthProviderSettingsnow includes passkey enrollment, listing, and removal- passkey sign-in can also return
emailVerificationRequiredwhen the app policy requires verified email before issuing app access
Policy-aware consumer behavior
The current recommendation is:
- load
client.getPolicy()orclient.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
authxaoapp 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, andcanResendAton the thrownAuthxaoOAuthPopupError - consumer apps can now start tenant SAML login flows through
client.getSamlStartUrl(slug, options?)orclient.startSamlRedirect(slug, options?) - tenant SAML metadata and manual callback completion are also available through
client.getSamlMetadataUrl(slug),client.getSamlMetadata(slug), andclient.finishSamlCallback(slug, { samlResponse, relayState }) StepUpPanelanduseAuthxaoStepUp()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:
LoginFormRegisterFormForgotPasswordFormResetPasswordFormSocialLoginButtonsAuthGateAuthSurfaceAuthModalAuthProviderSettingsVerifyEmailNotice
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
themeprop 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 })ForgotPasswordFormResetPasswordForm
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
- loads linked identities from
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 typecheckRequest 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:
AdministratorModeratorOwnerUser
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-scopeduserSettingsclient.getAppContext(appId)also exposes mergeduserSettings- 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()andgetAppContext()both expose mergeduserSettings
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/identitiesDELETE /api/auth/identities/:identityIdGET /api/auth/security-events?limit=25
Current behavior:
- password login is represented as a
PASSWORDidentity - 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:
rolescapabilitiesprogressionuserSettingsmembershipsessioncanManageRoles
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();