@hraness/suite-accounts provides the client and signed-protocol boundaries
for Hraness Accounts. It validates one product's registered binding, pins every
OAuth and OIDC trust value, keeps browser bearer custody server-side, and
parses suite identity and entitlement evidence from unknown.
Accounts remains the sole authority for account records, OAuth client registration, identity links, and entitlements. Installing this package does not let a product register itself or choose an issuer, JWKS endpoint, resource, callback, client ID, wire version, or trust algorithm.
Pin the immutable release:
{
"dependencies": {
"@hraness/suite-accounts": "github:hraness/suite-accounts#v0.3.4"
}
}Then install with Bun 1.3.14:
bun installReact and React DOM 18.3.1 through 19.x are optional peers. Install them only
when using @hraness/suite-accounts/react or
@hraness/suite-accounts/profile-form.
Pass the exact public fields assigned to the product. The factory rejects unknown fields, including attempts to supply authority-controlled trust data.
import { createSuiteAccountsClientConfiguration } from
"@hraness/suite-accounts/client-configuration";
const configuration = createSuiteAccountsClientConfiguration({
authMode: "oidc-rp",
callbackUrl: "https://hra.sh/api/suite-auth/callback",
clientId: "hraness:hra:production:v1",
consumer: "hra",
environment: "production",
origin: "https://hra.sh",
});
if (!configuration.ok) {
throw new Error(`Invalid Accounts binding: ${configuration.error}`);
}
configuration.value.provider.issuer;
// "https://account.hraness.com"The returned configuration is frozen. Its provider endpoints, resource, configuration version, and wire version are derived from the package's checked current authority data. The Accounts service independently enforces the same registration, so this client-side check never creates authority.
Version 0.3.4 retires the OPRTE browser client and origin from the current
authority. HRA at https://hra.sh is the sole current client for that product
line. The frozen v1 registry remains source-compatible for released readers,
and signed-protocol parsing still canonicalizes the predecessor oprte and
kitchen product IDs to hra. Signature verification uses the original
product bytes, so bounded predecessor receipts remain verifiable.
Local development still uses parseSuiteAccountsPublicConfig. The consumer
origin and both Accounts Convex origins must use one exact loopback hostname.
Remote configuration accepts only the checked production deployment.
Generated Vercel Preview surfaces can report their surface origin through
NEXT_PUBLIC_VERCEL_SURFACE_ORIGIN, but suite authentication remains
unavailable there.
Import provider-neutral identity parsers and signed-message builders from the
identity subpath:
import {
parseSuiteAccountId,
parseSuiteJwtClaims,
parseSuiteUsername,
suiteEntitlementReceiptMessage,
} from "@hraness/suite-accounts/identity";The identity catalog contains only the finite revisions, plan IDs, feature IDs, and plan-to-feature relationship required to verify signed evidence. Prices, provider lookup keys, product copy, and provider event replay policy are not part of this package.
parseSuiteJwtClaims performs structural parsing. It does not establish
signature, issuer, audience, or time trust. Use the registry-pinned verifier
for authorization.
| Subpath | Intended runtime |
|---|---|
. |
Dependency-light configuration, registry, URL, and Convex browser-token contracts |
./identity |
Provider-neutral identity types, parsers, views, and signed messages |
./identity/functions |
Opt-in Convex function references and billing transport types |
./identity/return-targets |
Opt-in Accounts-owned billing return-target identifiers |
./client-configuration |
Additive validated product-binding factory |
./browser-session |
Same-origin browser session reads and serialized refresh |
./oidc-rp |
Server-only OAuth 2.1 relying-party implementation |
./oidc-surface-server |
Registered browser-RP server handlers |
./bearer-verifier |
Server-only registry-pinned ES256 bearer verification |
./receipt-verifier |
Server-only HMAC receipt and product-keyring verification |
./convex-browser-auth |
Product Convex token configuration and identity parsing |
./convex-browser-auth-browser |
Memory-only browser bearer loader |
./convex-browser-auth-server |
Server-only short-token signing and JWKS handlers |
./auth-proxy |
Same-origin compatibility proxy with fixed headers and cookies |
./entitlements |
Post-signature entitlement checks and receipt ordering |
./profile |
Provider-neutral profile contracts |
./profile-form |
Optional controlled React profile editor |
./react |
Optional route-local Accounts Convex context |
The existing ./auth-client, ./public-config, ./registry, ./urls, and
other listed suite subpaths remain available for released clients. Import
server-only modules only from server code.
The package preserves these checks across the public surface:
- OAuth authorization code uses S256 PKCE plus exact state and nonce checks.
- Issuer, audience, origin, callback, client ID, resource, and endpoints must match the registered values.
- OAuth access and refresh tokens remain in encrypted HttpOnly cookies or server-to-server requests. Browser session JSON never exposes bearer tokens.
- Refresh-token rotation uses an origin-scoped exclusive lock and re-reads the session after acquiring it.
- Bearer verification accepts only bounded public P-256 ES256 keys from the pinned JWKS endpoint and enforces both client-binding claims.
- Product backends grant access only after receipt, replay, freshness, entitlement, and exact feature checks succeed.
- Missing legacy entitlement claims grant no suite features. Malformed claims invalidate the token.
Do not authorize from browser profile JSON, decoded JWT data, discovery destinations, billing plan membership, or an unverified receipt.
SUITE_CONSUMER_IDS, SUITE_ACCOUNTS_CONSUMERS,
SUITE_ACCOUNTS_DEPLOYMENTS, their policy arrays, and their lookup helpers
preserve the released v1 protocol registry byte for byte. They are deeply
runtime-frozen and deprecated for new consumers. Existing applications may use
them while migrating.
Current authority lives under the distinct
SUITE_ACCOUNTS_CURRENT_CONSUMER_IDS and
SUITE_ACCOUNTS_CURRENT_CONSUMERS exports and their current lookup helpers.
New registration remains an Accounts service change followed by a package
release and an exact factory binding. Retired client identifiers and routes are
rejected by current APIs.
The published v1 browser refresh-lock and session-notification channel strings also remain unchanged in version 0.1. Existing tabs therefore coordinate across a rolling package migration without a browser namespace cutover.
The compatibility registry is intentionally closed. It must not gain runtime mutation, remote discovery, environment overrides, or caller-supplied trust values.
This repository does not contain billing prices or provider lookup keys, authoritative registry writes, reconciliation jobs, email delivery, provider credentials, webhook payloads, provider project identifiers, or product-owned service policy. Those concerns belong to the Accounts service. The Convex function references and billing transport types required by existing clients are isolated behind explicit opt-in identity subpaths; the root and client configuration entries do not load them.
bun install --frozen-lockfile --ignore-scripts
bun run check
bun pm pack --dry-run --ignore-scriptsbun run check validates the portable portfolio inventory, runs independent
ESLint and TypeScript configuration, executes deterministic and property
tests, builds the ESM entries, scans the public boundary, and installs the
package in clean Bundler and NodeNext consumers on React 18.3.1 and 19.2.3. It
also builds the packed React entries in a clean Next.js 16.2 webpack consumer,
which verifies that every client entry has one valid top-level directive.
Read CONTRIBUTING.md before opening a pull request. Report suspected vulnerabilities privately as described in SECURITY.md.
MIT