Using it from another app
Nothing in the AussieAuth repo changes. The new app registers itself.
Register the app
Set the provisioning secret in that app's Convex, then have it POST its own config once — origins first, everything else optional:
# in the new app
bunx convex env set AUSSIEAUTH_SECRET "<the value from this deployment>"
await fetch(`${AUSSIEAUTH_URL}/apps/register`, {
method: "POST",
headers: {
authorization: `Bearer ${process.env.AUSSIEAUTH_SECRET}`,
"content-type": "application/json",
},
body: JSON.stringify({
slug: "portfolio", // stable id; survives a domain move
name: "Portfolio",
origins: ["https://portfolio.com", "http://localhost:5173"],
methods: ["google", "passkey"], // omit for all fifteen
}),
});
From then on those origins are trusted, they're in the passkey related-origins list, and sessions created from them are stamped with the slug.
Registration is idempotent, so calling it on boot and letting it re-run is the intended usage — that's what makes a wiped table repair itself.
POST /apps/unregister with {slug} takes it all back.
Add the client
Copy src/auth/ and src/lib/auth-client.ts into that app and point it at the
deployment:
// src/lib/auth-client.ts — the one line that changes per app
export const authClient = createAuthClient({
baseURL: import.meta.env.VITE_CONVEX_SITE_URL, // https://<deployment>.convex.site
plugins: [/* … */],
});
import { SignIn } from "./auth/SignIn";
<SignIn />;
The app never redirects to AussieAuth — it talks to the deployment from its own origin, so the only consent screen is the provider's.
<SignIn /> takes methods to narrow the list, featured to choose which
buttons sit on the front of the card, and primary for the form underneath them.
The client plugin shims in auth-client.ts import types from convex/lib/, so
copy that folder too, or keep both apps pointed at one checkout. Nothing under
src/auth/ imports Convex — the card talks to the auth server over HTTP like any
other client, so it works in a non-Convex app as well.
What origins are for
TRUSTED_ORIGINS still works and is now the bootstrap list — this site and
whatever you're developing against, so a fresh checkout works with an empty apps
table. Registered apps are added on top of it, per request.
An app's origins do double duty: they're the CORS allow-list and the WebAuthn
related-origins list, so registering is also what lets a passkey created on
aussieauth.com be used from that app. The list is served through
aussieauth.com/.well-known/webauthn, which vercel.json already proxies.
Scheme origins are filtered out of that list — a browser can't act on them, and every entry counts against WebAuthn's five-site limit.
Because browsers honour at most five distinct sites and silently ignore the
rest, /apps/register answers with the slot usage:
{
"slug": "portfolio",
"origins": 2,
"passkeyOrigins": {
"limit": 5,
"active": ["https://aussieauth.com", "https://portfolio.com"],
"dropped": []
}
}
If your app's origin shows up in dropped, passkeys won't work from it —
unregister something or consolidate onto fewer sites.
Method allow-lists
The per-app methods list is enforced at /sign-in/social rather than at the
callback, so a blocked provider never gets as far as showing you its consent
screen.
It fails open for origins no app has claimed, which is what keeps a deployment's own sign-in page working with an empty table.
Questions
Do I have to redeploy AussieAuth to add an app? No. Registration is a runtime HTTP call against the registry; the trusted-origin list is resolved per request.
What happens if two apps claim the same origin? The second registration is refused rather than silently reassigned — taking over an origin would mean taking over that app's sign-ins.
How quickly does a new registration take effect? Within five seconds. The registry is cached per isolate for that long; the isolate that handled the registration invalidates its copy immediately.
Can I use this without Convex on the frontend?
Yes. src/auth/ imports no Convex. Only the backend is Convex-specific.