Cargo Accounts · One Login · Integration Guide
one.cargo.ac (Cargo Account) Guide
The account home — the ONLY place credentials live. It has real login, signup and reset screens, validates each incoming `return` URL, and bounces every user straight back to the spoke they came from, signed in.
Applies to
one.cargo.acThe ecosystem at a glance
┌──────────────────┐ passwords live ONLY here
│ one.cargo.ac │ login · signup · reset
│ (account home) │◄───────────────┐
└────────┬─────────┘ │
return-redirect │ setSession() │ same-window
(?return=...) ▼ │ handoff
┌──────────────────┐ ┌───────┴────────┐
│ auth.cargo.ac │ │ one.cargo.ac │
│ tokens · JWKS · │◄──────►│ (this spoke) │
│ shared session │ silent │ one.cargo.ac │
└──────────────────┘ probe └────────────────┘
1 button · 1 tab · automatic return — no popup, no manual reopen.The uniform button — both states
Every app renders this exact control. Left: no session yet. Right: silent probe found a session, so one click continues.
No session
Session detected
0. You are the account home — build real auth here
one.cargo.ac is the ONE place credentials live. Unlike every other spoke, you DO build and keep working login, signup and password-reset screens, backed by the shared auth.cargo.ac backend. Every other app sends its users to you and waits for you to send them back.
Shared backend: reached only via https://auth.cargo.ac You render: /login /signup /reset-password (real, functional) No JWKS / Third-Party Auth step — you SHARE the backend, not trust it.
1. Read and validate the incoming `return` URL
Spokes arrive as /login?return=<spoke>/auth/callback. Read that param and validate it against the redirect allowlist (open-redirect guard). Keep it through the whole sign-in so you know exactly where to bounce the user back.
const params = new URL(location.href).searchParams;
const returnUrl = params.get("return");
// MUST be on the allowlist — reject anything else:
if (returnUrl && !isAllowlisted(returnUrl)) throw new Error("bad return URL");2. Sign the user in (real forms, shared backend)
Run your normal email/password and Google flows against the shared backend with signInWithPassword / signInWithOAuth, and signUp on the signup screen. This is the only app allowed to do this.
await authClient.auth.signInWithPassword({ email, password });
// or Google:
await authClient.auth.signInWithOAuth({ provider: "google" });
// signup screen:
await authClient.auth.signUp({ email, password });3. After success, return the user to the spoke (same tab)
The moment sign-in or sign-up succeeds, send the user BACK to the validated return URL in the SAME window. They never close or reopen the spoke — they land there already signed in. If there is no return URL, show your own dashboard.
// SAME-WINDOW bounce back to the originating spoke:
if (returnUrl) {
window.location.assign(returnUrl); // e.g. https://<spoke>/auth/callback
} else {
window.location.assign("/dashboard"); // arrived directly at one.cargo.ac
}4. Signup carries the return through too
New users sent from a spoke land on /signup?return=<spoke>. Carry the return param across the signup → (optional verify) → signed-in steps so brand-new accounts also bounce straight back to the spoke they started on.
// Preserve return across the signup flow:
<a href={"/login?return=" + encodeURIComponent(returnUrl)}>Already have an account?</a>
// After signUp success: window.location.assign(returnUrl ?? "/dashboard");5. Honor global logout
Because you own the shared session, your sign-out must revoke it (and refresh tokens) so every spoke's next silent probe returns login_required. Keep the redirect allowlist in sync below.
https://admin.cargo.ac https://admin.cargo.ac/auth/callback https://api.cargo.directory/auth/v1/callback https://api.cargoworks.ai/auth/v1/callback https://api.cargoworks.io/auth/v1/callback https://auth.cargo.ac https://cargo.ac https://cargo.email https://cargo.email/auth/callback https://cargo.email/auth/silent https://cargodirectory.io https://cargodirectory.io/auth/callback https://cargodirectory.io/auth/silent https://cargoworks.ai https://cargoworks.ai/auth/callback https://cargoworks.ai/auth/silent https://cargoworks.io https://cargoworks.io/auth/callback https://cargoworks.io/auth/silent https://cargoworks.network https://cargoworks.network/auth/callback https://cargoworks.network/auth/silent https://cargoworks.support https://cargoworks.support/auth/callback https://cargoworks.support/auth/silent https://cloud.cargoworks.network https://cloud.cargoworks.network/auth/callback https://cloud.cargoworks.network/auth/silent https://delivery.cargoworks.network https://delivery.cargoworks.network/auth/callback https://delivery.cargoworks.network/auth/silent https://exchange.cargoworks.network https://exchange.cargoworks.network/auth/callback https://exchange.cargoworks.network/auth/silent https://exim.cargoworks.ai https://expert.cargoworks.network https://expert.cargoworks.network/auth/callback https://expert.cargoworks.network/auth/silent https://global.cargo.directory https://id.cargoworks.network https://id.cargoworks.network/auth/callback https://id.cargoworks.network/auth/silent https://one.cargo.ac https://one.cargo.ac/auth/callback https://track.cargoworks.io
Worked example — a spoke hands a user to you and you return them
A user on exim.cargoworks.ai (no session) clicks "Continue with Cargo Account". They arrive at one.cargo.ac/login?return=https://exim.cargoworks.ai/auth/callback. They sign in. You immediately bounce them back — same tab — to that callback, where exim finishes signed in.
1. exim → window.location.assign(
"https://one.cargo.ac/login?return=" +
encodeURIComponent("https://exim.cargoworks.ai/auth/callback"))
2. one.cargo.ac validates return, shows login form, user signs in.
3. one.cargo.ac → window.location.assign(
"https://exim.cargoworks.ai/auth/callback?code=...")
4. exim exchanges code, sets session, lands on its dashboard. ✅What to delete, keep and add
- KEEP & BUILD: real login, signup and password-reset screens
- KEEP: the shared auth.cargo.ac backend (signInWithPassword / signUp)
- ADD: read + allowlist-validate the `return` URL on every entry
- ADD: same-window bounce back to the spoke after success
- ADD: global logout that revokes the shared session + refresh tokens
- DON'T: add a separate data backend or a JWKS Third-Party Auth issuer
Pitfalls & FAQ
- Should I open the login in a popup or new tab?
- No. Always a SAME-WINDOW, full-page redirect (window.location.assign). The user must never have to close and reopen your app.
- What about the return URL?
- It is REQUIRED on every handoff, must point at your own /auth/callback, and must be on the cargo.ac redirect allowlist. one.cargo.ac rejects any return URL that is not allowlisted.
- Do I need JWKS / Third-Party Auth here?
- No. one.cargo.ac shares the auth.cargo.ac backend, so you use setSession()/the shared client directly. JWKS trust is only for spokes with their OWN backend.
7. Test checklist
Confirm each item before flipping production traffic to cargo.ac.
- Real, working login + signup + password-reset screens are present
- Incoming `return` URL is read AND validated against the allowlist
- After sign-in success the user is bounced BACK to the spoke (same tab)
- After signup success new accounts also bounce back to the originating spoke
- No separate data backend / no JWKS Third-Party Auth issuer added
- Global logout revokes the shared session + refresh tokens
- Arriving directly (no return) lands the user on the one.cargo.ac dashboard
- S3/S4 round trip verified: spoke → one.cargo.ac → spoke, signed in, same tab
