Skip to content
rw3iss Auth

Applications

Registering and configuring applications — the consuming apps of the auth platform — via client.apps. Every route here is system_admin only; sign in with an admin account first.

Reference: AppsModule · AppRecord · App registration guide

Instantiate + sign in as admin

import { createAuthClient } from '@rw3iss/auth-client';
const client = createAuthClient({
apiBaseUrl: 'https://auth.ryanweiss.net/api/v1',
appCode: 'auth-client-demo', // an app the admin can log in to
});
await client.ready();
await client.auth.login({ email: 'admin@ryanweiss.net', password: '…' });

Register an app (basic / default config)

The minimal app: a code, a name, redirect URLs. Users live in the shared default pool, any email domain may register, first login self-grants access:

const app = await client.apps.create({
code: 'my-app',
name: 'My App',
allowed_redirect_urls: ['https://my-app.example.com/auth/callback'],
auto_grant_on_signup: true,
});
console.log(app.id, app.status); // 'active'

Register an app with its OWN user pool

Pools segregate identity — email is unique per pool. Give the app a dedicated default pool so its registrants are isolated from the shared platform users:

await client.apps.create({
code: 'partner-portal',
name: 'Partner Portal',
allowed_redirect_urls: ['https://partners.example.com/auth/callback'],
auto_grant_on_signup: true,
registration_namespace: 'partner-portal', // new users' home pool
read_namespaces: [], // nobody else may log in
});

Register an app on the EXISTING default pool, recognizing siblings

New users land in default; existing users from the claimleo and wristleo pools may also log in (and new registrants get tagged into those pools):

await client.apps.create({
code: 'claimleo',
name: 'ClaimLeo',
allowed_redirect_urls: ['https://claims.example.com/auth/callback'],
registration_namespace: 'default', // home pool for new users
read_namespaces: ['claimleo', 'wristleo'], // other pools (login)
});

Full pool semantics: User pools.

Modify an app’s config

client.apps.update(appId, body) is a PATCH — send only what changes. Everything except the immutable code is editable:

// Registration policy: restrict domains + methods, set a default org
await client.apps.update(app.id, {
allowed_email_domains: ['ryanweiss.net'],
allowed_auth_methods: ['password', 'google'],
default_organization_id: orgId, // '' clears
});
// Frontend URL — where account emails (verify/reset/invite) link to.
// Mind the blast radius: a wrong value strands those flows.
await client.apps.update(app.id, { frontend_url: 'https://my-app.example.com' });
// Webhooks — POSTed on every new-user registration through this app.
// hooks.slack.com URLs automatically get Slack {"text"} format.
await client.apps.update(app.id, {
webhooks: [{
name: 'Slack #signups',
url: 'https://hooks.slack.com/services/T…/B…/x…',
events: ['user.registered'],
enabled: true,
}],
});
// Disable logins without deleting the app
await client.apps.update(app.id, { status: 'disabled' });

Webhook payload + delivery semantics: App registration → Webhooks.

List / inspect / delete

const apps = await client.apps.list(); // every registered app
const one = await client.apps.get(app.id); // single row
await client.apps.delete(app.id); // soft-delete (audit kept)

See also

  • Users — granting users access to an app.
  • User pools catalogclient.pools.list() for type-ahead pool pickers.