@microvoidio/authx
v0.3.0
Published
AuthX application clients and Fetch API request authentication for managed identity integrations.
Readme
@microvoidio/authx
The single public SDK for AuthX first-party application integration.
@microvoidio/authxprovides the framework-neutral Application Session client and stable shared types.@microvoidio/authx/reactcomposes Better Auth React Session and Organization hooks with the in-memory Application Session Token client and exports the productionSignInButton,UserButton, andOrganizationSwitchercomponents.@microvoidio/authx/servervalidates issuer-fixed application discovery, verifies Application Session JWTs through its fixed/oauth/jwks.json, verifies opaque API Keys through the fixed online endpoint, and returns a stable Session/API Key Principal union.
The server requires a non-empty exact authorizedParties allowlist. It
validates the Session JWT azp against that allowlist in addition to issuer,
Project audience, Environment, algorithm, kid, signature, and expiry. There
is no permissive default.
The client never persists Application Session Tokens. The server export also
provides authx.apiKeys.create/list/rotate/revoke against the canonical
Project-scoped management API. Each call takes the inbound Request as an
explicit security context: it forwards only either the AuthX Session Cookie
with exact Origin/CSRF, or an admin Bearer. Project and Environment remain fixed
at client construction. Create and rotate return the plaintext only in their
one-time result; list and revoke types contain metadata only. The export exposes
no persistence, Prisma, or Better Auth server types.
Settled Application Session Tokens are never reused across calls; the client
only deduplicates issuance calls that are simultaneously in flight. Consumers
switch Organization through the SDK's controlled setActiveOrganization
mutation, which invalidates in-flight issuance before the Better Auth mutation
starts. This fail-safe model does not depend on a React hook render committing,
and an aborted or StrictMode render cannot create a hidden cache context.
Already-issued tokens remain offline-verifiable until their maximum 300-second
expiry; source Session or policy revocation blocks new issuance but is not
token introspection.
Every React Better Auth browser request carries the public Project ID in both
X-AuthX-Project-Id and the authx_project_id query routing hint. The query
value exists because browser preflights include requested header names but not
their values; AuthX requires the actual query/header values to match exactly
and authorizes the exact Origin against that Project's current-environment
policy. This route family is limited to Session read, Organization active/list
read, Organization set-active, Application Session issuance, and canonical
logout.
The public control-plane Project resource now exposes read-only
application_id; in the current one-Application-per-Project model it is
byte-for-byte equal to the Project ID configured here. The SDK continues to
require that explicit Project ID at construction and never guesses or falls
back to another Application identifier.
Authorized reads return the readable authx_csrf double-submit value in
X-CSRF-Token; the SDK holds it only in memory. Organization set-active and
POST /logout send that value and invalidate Session, Organization, and
Application Token contexts before and after the mutation. The SDK never calls
Better Auth stock /api/auth/sign-out. Sign-in does not require a pre-existing
CSRF cookie.
React
Create one client before rendering the zero-configuration components:
import { createAuthXClient } from "@microvoidio/authx/react";
export const authx = createAuthXClient({
projectId: "project_nexus_production",
frontendURL: "https://auth.nexus.example",
});import {
OrganizationSwitcher,
SignInButton,
UserButton,
} from "@microvoidio/authx/react";
export function Login() {
return <SignInButton returnTo="/" />;
}
export function AccountMenu() {
return (
<>
<OrganizationSwitcher />
<UserButton />
</>
);
}SignInButton derives the application Origin from the browser and links to the
Project-bound /api/auth/application/sign-in handoff. AuthX validates the
exact Project, Frontend Gateway, authorized Origin and Party before issuing a
short-lived signed continuation to Hosted Sign-in, then validates all of those
boundaries again before returning to the application. This first-party flow
never enters OAuth authorization or consent.
For SSR, set the public application Origin explicitly and pass the client
prop when needed:
createAuthXClient({
projectId: "project_nexus_production",
frontendURL: "https://auth.nexus.example",
applicationURL: "https://nexus.example",
});returnTo accepts only an application-local absolute path. Cross-origin and
scheme-relative values fall back to the current safe application path, URL
fragments are removed, and credential-like query parameters are stripped,
including camelCase and separator variants such as accessToken,
client-secret, api.key, and codeVerifier. Hosted navigation never
receives credentials.
The components use native links, buttons, disclosure, labels, and select
controls. They expose loading, signed-out, empty, and safe error states without
rendering upstream response details. Sign-out and Organization switching use
the credentialed Better Auth browser client, preserving its Session Cookie,
Origin, CSRF, and Project boundaries. The SDK never reads the HttpOnly Cookie
or stores credentials or Application Session Tokens. After a successful
Organization switch, onOrganizationChange lets the application clear its
Organization-scoped caches before loading business data.
OrganizationSwitcher treats a signed-out Session as authoritative even if an
upstream Organization hook is stale: cached Organization names are not
rendered while signed out.
The server Principal discriminator is exactly "session" | "api_key".
"session" denotes an Application Session JWT backed by a signed-in account;
"user" is not a public Principal type.
Server
import { createAuthXServer } from "@microvoidio/authx/server";
export const authx = createAuthXServer({
issuer: "https://authx.microvoid.io",
projectId: "project_nexus_production",
environment: "production",
tenantModel: "BOUND_ORGANIZATION",
authorizedParties: ["https://nexus.microvoid.io"],
});tenantModel is mandatory and must match the Project policy. NONE forbids
tenant claims, PROJECT_TEAM requires selectedTeamId, and
BOUND_ORGANIZATION requires organizationId. Every Session Principal
includes signedUpAt; legacy tenant_id claims fail closed.
Nexus integrations may import NEXUS_PERMISSION_CATALOG,
NEXUS_ROLE_PERMISSIONS, and NEXUS_MANAGEMENT_API_KEY_POLICY from the
package root. The presets freeze the default owner/admin/operator/billing/viewer
mapping, nexus-management, nxs_mk_, nexus_workspace, workspace_id, and
the stable Nexus permission strings without importing Nexus source code.
Publishing
The current release candidate is @microvoidio/[email protected]. This is a
breaking Application Session Principal contract: tenantModel is mandatory,
tenant_id is forbidden, NONE forbids tenant claims, PROJECT_TEAM
requires selected_team_id, and BOUND_ORGANIZATION requires org_id.
Session Principals also require signed_up_at. Consumers must upgrade in the
same hard-cut window as the AuthX token issuer. Publication must use the
guarded repository command, which explicitly selects the public npmjs registry
and public scoped-package access:
pnpm --dir packages/sdk run publish:npmjsThe prepublishOnly gate rejects publication if npm resolves any registry
other than https://registry.npmjs.org/. Packaging remains limited to
package.json, this README, and the allowlisted ESM/type files under
dist/src; source maps, declaration maps, tests, source files, and private
@authx/* runtime dependencies are excluded.
