AUTH GUIDE / Technical reference
Exact contracts, complete examples
Technical reference
The complete integration guide for your developer, your agent, or a deeper read. Examples use this environment’s auth host: alkeyon.fastflow.tech.
Start with a product scenario · See the architecture · Read OpenAPI
Choose your product’s identity model
Start with FlowPrime Identity to explore the business shape. Use this guide to connect that shape to client registration, hosted screens and the authority your app receives. Creating a login, granting a customer account and granting access to a paid feature are separate steps.
For product users, register a customer surface client. Public signup is controlled by AllowSelfRegistration; account creation on verified signup by SignupGrantsAccount; consumer access by ConsumerAccountId. A CheckoutUrl gives an unseated user a way forward. Configure the product’s billing and entitlement policy separately.
| Product shape | Client policy and prerequisites | First journey |
|---|---|---|
| Sign up, then buy | AllowSelfRegistration=true; SignupGrantsAccount=false; no consumer pin; a checkout URL. | Signup creates an identity. Without a seat or redeemable grant, login shows purchase guidance. A successful purchase can supply the owner grant redeemed at login. |
| Free workspace or trial | AllowSelfRegistration=true; SignupGrantsAccount=true; declare FreeTier as default_plan or trial_grant and configure the corresponding license policy. | Verify email, receive the signup owner grant, then sign in to the customer account. Your app checks the entitlement; declaring FreeTier in auth alone does not activate a plan. |
| Consumer app | AllowSelfRegistration=true; SignupGrantsAccount=false; pin ConsumerAccountId to your account. | An unseated customer signs in as consumer in the pinned account. Separate personal data by subject as well as account. |
| Checkout-first with teams | AllowSelfRegistration=false; SignupGrantsAccount=false; no consumer pin; purchase-to-grant integration. | Purchase starts onboarding. The recipient establishes or uses their login, then redeems the grant and arrives as account owner. |
| Internal tool or closed group | AllowSelfRegistration=false; SignupGrantsAccount=false; existing customer account and owner invitations. | The owner invites a person. Acceptance creates a seat; login opens that account. For your platform administration consoles, use a separate platform-surface client. |
| Closed consumer product | AllowSelfRegistration=false; SignupGrantsAccount=false; ConsumerAccountId configured; controlled onboarding. | An admitted customer can use the pinned account as consumer. Closing signup does not itself enforce payment: your app must check any paid entitlement. |
A real seat takes precedence over the consumer pin. The same person may therefore arrive as owner or member rather than consumer. Test both branches before choosing a data-access policy.
One identity, several workspaces and accounts
One email and password establish the person’s platform identity. Credentials live centrally; authorization is resolved again for the organization, client and customer account being entered. A platform login is not permission to read every product.
| Layer | What it owns | What your app must understand |
|---|---|---|
| Platform identity | The person’s credentials, platform session and workspace directory. | The master token has its own audience and token purpose. It is not a product API bearer token. |
| Operator organization / workspace | The builder’s applications, domains, branding and staff. | An organization boundary is distinct from a buying customer’s account. Tenant context must match the registered app. |
| Customer account / workspace | One customer company and its owner/member seats. | A customer token names one account. Select another account by an authorized switch that reissues the token. |
| Product permissions | Your app’s records, roles and paid capabilities. | Auth establishes identity and account membership. Your app enforces record ownership, operation permissions and entitlements. |
Single login and separate sessions
The platform dashboard opens an organization using a short-lived, single-use handoff. The receiving organization establishes its own session. A product’s OIDC flow then establishes the product cookie. Existing valid identity sessions can avoid another password prompt, but MFA, consent, account choice or a missing session can still require interaction.
Do not share a cookie across unrelated domains or pass the master token into a product API. Cross-workspace handoff and switching customer accounts are different operations. SDK /switch-org and the old org=pick integration are retired.
The same person can be staff and a customer
A platform-surface client receives staff authority. A customer-surface client receives customer/account authority and suppresses that person’s staff privileges. Opening the product as its customer must not grant administration access merely because the person also owns the operator workspace.
Register a new application
- Choose the operator organization and environment. Obtain its slug and the auth issuer, expected access-token audience and supported package/feed details for that environment.
- Choose
surface=customerfor the product orsurface=platformfor staff consoles. Use separate registrations for the two surfaces and separate credentials per environment. - Register the exact HTTPS callback, requested scopes and grant types through the organization’s Applications settings or the org-admin API below. Keep the client secret in server configuration.
- Apply the signup, account-grant or consumer policy from your scenario. Configure billing separately when the app requires a subscription.
- Wire the SDK or OIDC callback, protect your routes and enforce the account boundary. Set the organization’s Home URL and the app’s checkout destination deliberately.
- Run login, refusal, account switch, recovery and logout in the same browser, ending on your product. Confirm the resulting identity and permissions, not only a successful redirect.
This example creates a confidential customer web client through an authenticated org-admin request. Replace every placeholder, and send it to the organization’s auth host in the selected environment.
POST https://your-org.alkeyon.fastflow.tech/v1/orgs/your-org/apps
Authorization: Bearer <org-admin-access-token>
Content-Type: application/json
{
"name": "My product - staging",
"scopes": "openid email profile org",
"grantTypes": "authorization_code,refresh_token",
"redirectUris": ["https://app.example.com/auth/callback"],
"surface": "customer",
"allowSelfRegistration": false,
"signupGrantsAccount": false,
"checkoutUrl": "https://www.example.com/pricing"
}
Store the returned clientId and clientSecret securely. The example assumes a company product whose access comes from a purchase grant or an accepted invitation. Client registration alone creates neither a subscription nor a seat.
For a browser-only public client, never ship a secret in JavaScript. Use an authorized public-client registration and authorization code with PKCE. Dynamic registration has its own restrictions; see MCP and agent integrations.
.NET: hosted login and a protected app
Install Alkeyon.Sdk from the package source provided with your integration. Configure the registered client and use the cookie integration for server-rendered pages. The complete minimal application below returns the selected account only after authentication and customer-context checks.
dotnet add package Alkeyon.Sdk{
"FFAuth": {
"AuthDomain": "alkeyon.fastflow.tech",
"DefaultOrg": "your-org",
"ClientId": "your-registered-client-id",
"Audience": "your-configured-access-token-audience",
"Scopes": "openid email profile org"
}
}
Supply FFAuth__ClientSecret through your deployment’s secret store. AuthDomain is a bare host; the SDK constructs HTTPS URLs. The access-token audience is not automatically the OIDC client ID.
using Alkeyon.Sdk;
var builder = WebApplication.CreateBuilder(args);
builder.AddFFAuth();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapFFAuthEndpoints();
app.MapGet("/", () => Results.Content(
"<a href='/auth/login'>Sign in</a>", "text/html"));
app.MapGet("/account", (HttpContext context) => {
var user = context.User;
if (user.GetOrgSlug() != "your-org" || !user.IsCustomer()
|| user.GetAccountId() is null)
return Results.Forbid();
return Results.Ok(new {
account = user.GetAccountId(),
role = user.GetAccountRole()
});
}).RequireAuthorization();
app.Run();
For real records, scope every query and mutation to the validated account; for consumers, include the validated subject too. Add your own operation permissions, entitlement checks and CSRF protection for cookie-authenticated writes. Behind a reverse proxy, configure forwarded headers only for trusted proxies so callbacks use the registered external HTTPS origin.
AddFFAuthWithBearer() adds the SDK’s API bearer integration for /v1 alongside browser cookies. Confirm the intended scheme for other API paths rather than assuming every route uses bearer authentication.
Optional client provisioning at startup
Call builder.AddFFAuthProvisionedClient() before AddFFAuth() when your deployment owns an org-scoped provisioning client. Under FFAuth:Provision, supply OrgSlug, that provisioning ClientId/ClientSecret, AppName, comma-separated RedirectUris and a persistent CacheFile. Explicitly set Surface and your scenario’s policy fields there.
The provisioning endpoint is POST /v1/orgs/{slug}/apps/provision. Re-registering the same name rotates its secret, so use a distinct name per deployment and retain the credential cache across restarts. Product deployments use their organization’s provisioning credential; the platform-wide provisioning key is not an app credential. Changing cached provisioning configuration is not an automatic policy migration: update the registered client deliberately.
Any language: authorization code with PKCE
Use a maintained OIDC client library. Start from the organization’s discovery document, validate its issuer against your configured expectation, and use the published authorization and token endpoints. Do not construct an issuer from an untrusted token or silently disable issuer validation to resolve a mismatch.
- The app creates fresh state, nonce and a PKCE verifier; retain them in a protected, expiring browser-bound session.
- Redirect to the authorization endpoint with a registered callback and the S256 challenge.
- Auth handles sign-in, verification, MFA, consent and customer-account selection as needed.
- The callback checks state and exchanges the single-use code with the same redirect URI and the PKCE verifier. A confidential client authenticates with its secret.
- Validate the ID token’s signature, issuer, lifetime, nonce and client-ID audience. Validate the access token separately for the intended API. Establish the app session, then return to a validated local destination.
The following requests are schematic; URL-encode query and form values.
GET https://your-org.alkeyon.fastflow.tech/Connect/Authorize
?response_type=code
&client_id=<registered-client-id>
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fauth%2Fcallback
&scope=openid%20email%20profile%20org
&state=<random-state>
&nonce=<random-nonce>
&code_challenge=<base64url-sha256-of-verifier>
&code_challenge_method=S256
POST https://your-org.alkeyon.fastflow.tech/v1/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=<client-id>&client_secret=<server-secret>&code=<code>&redirect_uri=<same-encoded-callback>&code_verifier=<verifier>
Public clients omit the secret and must use their permitted public-client authentication method. If the client is enabled for a strict resource-bound grant, include the same approved resource during authorization and code exchange; see recipient-bound access.
A successful auth session does not imply a seat in every app. Handle access_denied as an authorization outcome and show a route to the product’s invitation or checkout flow.
Go integration
The Go package supplies JWT validation, HTTP auth endpoints, PKCE helpers and tenant middleware. It is a separate SDK: do not assume that .NET cookie revalidation, account switching or recipient-policy helpers exist in Go.
Use the module source and version supplied for your integration. Its module import is gitea.lab/fastflowtech/auth/sdk/go-sdk/ffauth; that private module path requires configured repository access and is not a public package-install promise.
opts := &ffauth.Options{
AuthDomain: "alkeyon.fastflow.tech",
DefaultOrg: "your-org",
ClientID: configuredClientID,
ClientSecret: configuredClientSecret,
Audience: configuredAccessTokenAudience,
CallbackURL: "https://app.example.com/auth/callback",
StateCookieSecret: configuredStateCookieSecret,
}
Set a stable, securely generated state-cookie key (32-byte key encoded as hex) and an explicit callback URL. Use NewJWTValidator with your configured audience and the HTTP middleware for bearer validation. The Go helper currently validates the ID token but does not send an OIDC nonce, does not rotate refresh tokens, and points logout at the legacy /v1/connect/logout route. For a new browser integration, use a maintained OIDC library or supply these missing lifecycle pieces, checking behavior against the full OIDC recipe; implement any missing nonce, ID-token, refresh, revocation and logout requirements in the app or a maintained OIDC library.
Python integration
The Python ffauth package validates JWTs and exposes an AuthContext. It does not supply the .NET hosted-login callback, account switcher or browser-session lifecycle. Obtain the package through the integration’s configured package source.
from ffauth import JWTValidator, AuthOptions
validator = JWTValidator(AuthOptions(
auth_domain="alkeyon.fastflow.tech",
audience=configured_access_token_audience,
issuer=configured_expected_issuer,
))
auth = validator.validate(access_token) # raises AuthError on refusal
if auth.org_slug != "your-org" or not auth.is_customer:
raise PermissionError("Customer access required")
account = auth.claims.get("account")
if not account:
raise PermissionError("Customer account required")
# Apply account/subject ownership and operation checks before reading records.
Always configure the expected audience. Use an OIDC library for interactive sign-in and the separate ID-token checks, then apply the same account and entitlement rules as every other app. A strict recipient integration also needs the purpose, client and actor checks in the recipient contract; basic JWT validation alone is insufficient.
White-label login and direct product return
Your operator organization owns branding, locale and domains. Its customer accounts share that organization’s branding; creating a customer account does not give it independent domain or identity-provider settings.
- Register the app’s exact public HTTPS callback, including callbacks on supported custom domains. Configure custom domains through the organization’s domain settings and finish the required DNS and TLS setup.
- Set branding in Organization Settings: product name, colors, logo and supported locale. Confirm the actual login, verification, invitation and recovery screens.
- Set
HomeUrlto the product’s normal entry URL. Set the customer client’sCheckoutUrlto the intended purchase or access-information page. - Start login through your app’s auth entry point. It redirects to the org-scoped hosted authorization flow and keeps the OIDC state needed for a secure callback.
- Preserve the originating client through hosted signup, email and recovery continuations. Finish at the product in the same browser, including after verification and password reset.
PUT https://your-org.alkeyon.fastflow.tech/v1/orgs/your-org/home-url
Authorization: Bearer <org-admin-access-token>
Content-Type: application/json
{"homeUrl":"https://app.example.com/"}
Which return destinations are trusted?
A registered active OIDC callback origin can be used for a plain product return, including a deep link on that origin. The product then runs OIDC and can reuse the existing hosted session. Scheme, hostname and port matter; registering one host does not trust its sibling subdomains. Unknown or inactive origins do not become valid just because a request supplies returnUrl.
A plain product return is not a completed OAuth callback: it carries no invented authorization code. Some legacy federation destinations have a separate code flow; new OIDC apps should use the registered OIDC callback.
When no explicit continuation is available, product-entry resolution uses the published Home URL and eligible customer-client destinations. Configure those URLs explicitly, especially when one organization has several products, and carry the originating client rather than relying on an incidental default.
Signup, purchases and account grants
Public signup belongs to a client’s policy. Use the registered client’s authorization flow to retain its context, including the expected callback. The organization-level registration setting is not a substitute for the customer client’s signup policy.
- Bare signup: establishes a customer identity after the required verification. It does not grant staff authority or create an invitation seat.
- Signup account grant: with
SignupGrantsAccountenabled, verified signup earns an owner grant; login redeems it into a customer account. The declared free-tier mode and actual license policy must agree. - Purchase: the billing integration records a grant for the intended recipient. The recipient’s login redeems it. Paying on behalf of another person must not assign their access to the payer’s current session.
- Consumer: an eligible unseated customer enters the configured consumer account. The app still owns per-person records and any payment gate.
A successful login does not prove payment or activate an entitlement by itself. Check the product’s license decision before paid operations. Test the real hosted payment and email path separately from mock checkout and captured dev mail.
Staff teams and customer teams
Keep two rosters distinct. Organization members administer the operator workspace through platform-surface clients. Customer account members use a product through customer-surface clients. An organization’s org_admin is not automatically the owner of every customer account.
Link to the hosted customer team
Where the customer-team surface is deployed and verified for your integration, start a new hosted flow on the organization’s auth host:
https://your-org.alkeyon.fastflow.tech/Customer/Account/Team
?client_id=<managed-customer-client-id>
&account=<selected-account-id>
&returnUrl=<encoded-https-product-team-url>
The user must have a live seat. The return URL must match an origin registered to this exact active customer client; another client’s callback or the organization’s Home URL is insufficient for this surface. A consumer without a seat cannot use it. Keep the resulting protected continuation opaque and start a fresh entry after a new login. The hosted flow checks membership again for each action.
This dedicated team/profile/security flow has its own selected-account context and CSRF-protected logout. Do not substitute the operator’s administration pages. Confirm its availability and same-browser journey in your target environment before shipping the link.
Customer invitations are accepted, not silently applied
The account owner invites a person through the hosted team page or the account self-service API. A pending invitation becomes a seat after acceptance. An existing login can accept without creating another identity; a new person establishes their login on the invitation journey. Revoking an invitation or removing a member must remain effective on later login and refresh.
Support access follows the same owner-authorized seat flow. An old accepted invitation is not authority to restore a removed seat. Repair requires a fresh owner-authorized invitation and acceptance.
owner, member and consumer describe account roles. Your product maps those to its own operation permissions; labels such as supervisor or editor belong to that product’s permission model.
Multiple accounts and revocation
A person may own one customer account and hold seats in others. Selection uses the stored valid choice, then an unambiguous owned or sole seat; when a choice is needed, the hosted flow asks. The token names only the selected account.
The .NET SDK maps GET /my-accounts and POST /switch-account (form fields accountId, optional local returnUrl). The latter uses the current refresh session, validates the live seat and replaces the app cookie with newly validated claims. Submit it from the same origin; never let a browser-supplied account ID override token context without this check.
After a switch, reload account-scoped state and invalidate caches tied to the previous account. Refuse foreign accounts. Treat a removed stored selection as a need to resolve current access, not a reason to recreate the seat.
Revocation is not instantaneous for every credential. The .NET cookie is revalidated by default every five minutes; do not disable that check. A standalone signed bearer can remain usable until expiry unless its resource server checks revocation. Test the boundary your app actually uses.
Recovery and logout return to the product
Use hosted password reset, email verification and MFA recovery rather than collecting passwords in your app. Carry the product/client context through the email continuation and confirm the rendered sign-in link returns to the intended app. An account chooser or a refusal screen can be a valid outcome when current access needs a decision.
With the .NET SDK, /auth/logout clears the app session and redirects to hosted logout. A trusted return origin can go directly back to the product; an untrusted or missing destination can require confirmation. This does not promise that every independently established session in every product has been erased.
For another OIDC library, verify the advertised discovery metadata before assuming RP-initiated logout is supported. If it is not advertised, clear your app session and use the documented hosted logout flow. Test re-entry to a protected page after logout.
Multi-factor authentication
Hosted sign-in can require TOTP and provides enrollment and recovery-code flows. Let the hosted flow finish before creating the app session. A challenge credential is not a customer API access token.
Test an enrolled user, a rejected code, recovery and the final product callback. Successful password login in a fixture without MFA is not evidence for this path. Organization policy and the centrally held credential determine the required challenge.
Machine integrations
Use client_credentials for a backend acting without a person’s interactive login. A platform client receives a service projection. A customer-surface machine client must be pinned to a live service user and account through ServiceUserId and ServiceAccountId; missing or removed seats are refused.
POST https://your-org.alkeyon.fastflow.tech/v1/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=<machine-client>&client_secret=<server-secret>
Validate the resulting audience, tenant, account and granted scopes at the receiving API. Limit the machine to its intended operations. A consumer pin is not a substitute for a machine seat, and a confidential service secret must never be exposed to a browser or an agent’s prompt.
API keys
API keys are a separate credential type for supported integrations. Use the key-management and validation endpoints in the published API contract, and distinguish a user/integration key from an organization provisioning credential.
Validate server-side, enforce the returned principal’s tenant and allowed operations, and retain key revocation behavior. Do not use a broad platform key to make a customer call succeed or to bypass a seat refusal.
MCP and assistants acting for a person
An assistant using interactive OAuth acts with the connected person’s granted authority. It does not acquire an independent staff role. Configure the org-scoped MCP server URL and follow that server’s protected-resource metadata to the appropriate authorization server.
When supported by the server/client combination, Dynamic Client Registration creates a customer-surface interactive client. DCR cannot choose privileged surfaces, service seats, consumer pins or signup grants. Use PKCE, validate the consented resource and preserve the selected customer account.
Client compatibility and resource policy matter. A registered client or a successful login alone does not prove the assistant can call the intended downstream API. Verify discovery, consent, a real tool call and denied access with the exact connector you intend to support.
Recipient-bound access and delegation
Resource-bound OAuth is an opt-in integration contract. It requires deployment-owned resource policy and compatible consumers; it is not enabled merely by passing a resource URL. Unactivated integrations retain their existing audience behavior.
- The browser grant names one approved HTTPS resource. Its access token is intended for that resource, carries
typ=at+jwt, a client identity, tenant and customer context, and is validated for that purpose. - The ID token still has the OIDC client ID as audience. Never use it as an API bearer.
- An approved confidential backend can exchange a customer token for a separate downstream token. The destination validates its own audience and the original actor chain. The original MCP token is not a downstream API credential.
- Policy, consent, scope, client and live-seat checks constrain exchange. Delegation is one hop; a DCR public client cannot be the exchange actor.
SDK 0.14.0 defines FFAuth:Resource and FFAuth:Recipient for this contract. Use them only with a published compatible package and an explicitly configured resource policy. Check the integration’s activation and acceptance status before migration; installing an SDK does not activate a live tenant. Basic Go/Python validators need the additional recipient, client and actor checks.
Validate tokens and maintain the session
- Use a configured trusted issuer and JWKS source, verify RS256 signatures and lifetime, and validate the intended audience. Handle key rotation by refreshing the trusted key set, never by trusting a token-supplied key URL.
- Validate tenant, token purpose and the surface/account context before authorization. Do not accept a platform master token or MFA challenge as a product credential.
- Store refresh tokens server-side or in protected session storage. Refresh a client session through the token endpoint with its bound client authentication, replacing the rotated refresh token atomically.
- On revocation or failed refresh, end the session and restart the authorized login flow. Do not retry using a less restrictive credential.
POST https://your-org.alkeyon.fastflow.tech/v1/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&client_id=<client-id>&client_secret=<server-secret>&refresh_token=<current-refresh-token>
The legacy /v1/auth/refresh endpoint serves hosted/legacy sessions; it is not a substitute for a client-bound OAuth refresh. Read token expiry from the response rather than hard-coding a duration. Follow the environment’s issuer contract: tenant-issuer migration and recipient activation are distinct changes.
Read the identity your app actually receives
| Context | Typical authority claims | Meaning |
|---|---|---|
| Staff on a platform client | org_slug, org_role, organization role | Operator administration. Account claims are suppressed even if the person also holds a customer seat. |
| Owner/member on a customer client | org_slug, org_role=slug:customer, account, account_role, account_owner_email | One customer account, with owner or member authority. No staff privilege is carried into the product. |
| Consumer on a pinned customer client | account=pinned account, account_role=consumer, sub | The operator’s clientele. Isolate each person’s records by subject as well as account. |
| Machine | grant_type, app/client identity, scopes; pinned account for a customer machine | A non-interactive grant with its own operation and account limits. |
| Master platform session | aud=alkeyon:platform, token_use=platform | Platform identity and handoff operations, not product APIs. |
| Hosted auth session | Hosted identity/organization context | Auth’s own pages resolve account access; this cookie is not the customer app’s client projection. |
org_role is canonical. ID tokens may also carry the legacy org_roles spelling during compatibility; do not require both. The raw .NET role claim uses the claim-type URI, so prefer SDK helpers over assuming a literal role property. ID tokens and access tokens have different audiences and purposes.
Do not infer permissions from email, organization display name or an unverified JWT payload. Use the validated subject, organization and account identifiers, then apply your app’s role and data policy.
Discovery and the current API contract
Download this environment’s OpenAPI document for exact request bodies, response schemas and endpoint security. The examples here teach journeys; use the published contract for the complete API.
Organization discovery:
https://your-org.alkeyon.fastflow.tech/.well-known/openid-configuration
https://your-org.alkeyon.fastflow.tech/.well-known/oauth-authorization-server
Configured platform key source:
https://alkeyon.fastflow.tech/.well-known/jwks.json
Use organization discovery for an organization’s interactive flow. Honor its published issuer and endpoints, while checking them against trusted configuration. A bare platform URL and an organization login URL serve different contexts.
Authentication API and hosted pages
New interactive integrations use authorization code with PKCE, /v1/connect/token and /v1/connect/userinfo. Auth’s hosted pages handle passwords, verification, recovery and account selection. Older direct-login endpoints are not a reason to collect passwords in a new app.
For request shapes and permitted credentials, follow OpenAPI. Do not treat an authentication response as proof of paid access.
Organization and account APIs
| Purpose | Route family | Authority |
|---|---|---|
| Client registration | /v1/orgs/{slug}/apps | Organization administration; provisioning has its separate scoped credential. |
| Branding and Home URL | /v1/orgs/{slug}/branding and /home-url | Organization administration. |
| Operator staff roster | /v1/orgs/{slug}/members and /invites | Staff administration, not customer self-service. |
| Customer team self-service | /v1/orgs/{slug}/accounts/mine and /mine/invites | The selected customer account; owner permissions for team changes. |
| Accept account invitation | /v1/orgs/{slug}/accounts/invitations/accept | Authenticated intended recipient and a valid invitation. |
| List/select customer seats | /v1/auth/my-accounts and /v1/auth/switch-account | Current user session and a live seat; SDK app helpers use shorter paths. |
Consult the endpoint’s published security requirements before calling it. A staff-members endpoint cannot replace the customer-account invitation flow.
External provider endpoints
Hosted auth starts provider sign-in at /auth/external/{provider} and receives its callback at /auth/callback/{provider}. These are provider-facing paths on auth. They are distinct from your application’s /auth/callback OIDC endpoint.
Configure provider credentials and callbacks in the organization’s settings; see social sign-in.
Registration policy reference
/v1/orgs/{slug}/registration exposes the organization registration setting. Product-specific allowSelfRegistration, signupGrantsAccount, consumerAccountId and checkoutUrl belong to the registered client’s policy. Use the scenario matrix and grant lifecycle together.
Do not enable public signup as a workaround for a missing invitation, or assume that setting a free-tier label in auth configures the license service.
Verify a complete integration
- A new permitted user completes the hosted journey and arrives in the intended product with the right account.
- A staff member entering as a customer has no staff authority in the app; a customer cannot open operator administration.
- Account A cannot read or change account B’s records. Consumers in the same pinned account cannot read each other’s private records.
- Invitation acceptance creates only the intended seat. Revoked invitations, removed seats and foreign account switches are refused.
- Verification, password reset, MFA and logout preserve the intended product destination in the same browser, including on the custom domain.
- Expired, wrong-issuer, wrong-audience, wrong-purpose and invalid-signature tokens fail. Refresh, key rotation and revoked-session handling work under the actual app middleware.
- Paid access is checked independently. A mock checkout or captured dev email is not proof of hosted payment or external delivery.
Troubleshooting by outcome
| What the user sees | What to check |
|---|---|
| Login succeeds but access is refused | Selected client surface, current seat or grant, consumer policy and entitlement. Do not grant staff permissions to resolve it. |
| Wrong app after reset or verification | Originating client, active callback origins, HomeUrl and CheckoutUrl; follow the exact email link in the same browser. |
| Issuer or audience rejected | Discovery issuer, access-token audience versus ID-token client audience, and whether strict recipient policy is active. |
| Login breaks after deployment | Registered callback, environment-specific client name, persisted provisioning cache, secret rotation and trusted proxy configuration. |
| Removed member still appears signed in | Cookie revalidation interval, refresh revocation and bearer expiry; distinguish a visible cookie from authorized API access. |
Collect only sanitized status codes, request/trace IDs, timestamps and visible destinations for diagnosis. Never include passwords, authorization codes, tokens, cookies or customer content in logs or support attachments.