# MyLogin.world MyLogin.world gives an app a public HTTPS sign-in page (Google, Apple, Microsoft, GitHub, passkeys and more) without a domain or certificate of its own. The app opens an outbound connection, receives the sign-in result, verifies it itself and keeps its own users and sessions. Nothing about users is stored here. Setup, once, in the dashboard at https://app.mylogin.world.compas.cs.stonybrook.edu: create a service with a name and the app URL (where the browser returns after sign-in). The service gets a sign-in address https://-.login.mylogin.world.compas.cs.stonybrook.edu: the service part is set per service, the account name once per account. That address is the only configuration the SDKs need. Docs: https://mylogin.world.compas.cs.stonybrook.edu/docs/quickstart (Node, Python, Go, plain HTTP) and https://mylogin.world.compas.cs.stonybrook.edu/docs/protocol. ## SDKs Node: npm install @mylogin/sdk; createAuth({ relayUrl, providers: { google: { mode: 'managed' } }, onIdentity }); adapters for Express, Fastify, Hono, SvelteKit; check with npx @mylogin/sdk doctor --relay
. Python: pip install mylogin-sdk; Auth(relay_url=..., providers={"google": managed()}, on_identity=...); adapters for FastAPI, Flask, Django; check with python -m mylogin doctor --relay
. Go: go get github.com/mferdman/mylogin.world-clients/sdks/go; mylogin.New(mylogin.Config{RelayURL, Providers, OnIdentity}); auth.Mount(mux); auth.RequireUser(handler). Every SDK serves GET /auth/login, GET /auth/status, GET /auth/me, POST /auth/logout and POST /auth/passkey/register on the app. onIdentity maps the verified identity to the app's own user and returns nothing to refuse. Managed providers need nothing registered; for your own OAuth client register
/oauth/cb with the provider and pass the client id and secret in mode "byo". Environment variable: AUTH_RELAY_URL. No API keys, tokens or key files exist. ## Custom domains A service may add one hostname of its own (Service › Settings › Custom domain), e.g. auth.example.com, with a CNAME to its permanent address. Certificates are issued automatically; the dashboard's Check verifies DNS and certificates and then makes the hostname the sign-in address. Managed providers keep working there with nothing to register (the consent screen names MyLogin.world); an own OAuth client uses redirect URI https:///oauth/cb. Passkeys are bound to the address they were created on. Set AUTH_RELAY_URL to https://; devices and apps set up through an integration are reconnected from the service page. Docs: https://mylogin.world.compas.cs.stonybrook.edu/docs/custom-domains. ## Integrations Ready-made, no code: Synology https://mylogin.world.compas.cs.stonybrook.edu/integrations/synology, Unraid https://mylogin.world.compas.cs.stonybrook.edu/integrations/unraid, Proxmox VE https://mylogin.world.compas.cs.stonybrook.edu/integrations/proxmox, pfSense https://mylogin.world.compas.cs.stonybrook.edu/integrations/pfsense, OPNsense https://mylogin.world.compas.cs.stonybrook.edu/integrations/opnsense, Pi-hole https://mylogin.world.compas.cs.stonybrook.edu/integrations/pihole, openmediavault https://mylogin.world.compas.cs.stonybrook.edu/integrations/omv, AdGuard Home https://mylogin.world.compas.cs.stonybrook.edu/integrations/adguard, Home Assistant https://mylogin.world.compas.cs.stonybrook.edu/integrations/homeassistant, Argo CD https://mylogin.world.compas.cs.stonybrook.edu/integrations/argocd, Audiobookshelf https://mylogin.world.compas.cs.stonybrook.edu/integrations/audiobookshelf, BookStack https://mylogin.world.compas.cs.stonybrook.edu/integrations/bookstack, Forgejo https://mylogin.world.compas.cs.stonybrook.edu/integrations/forgejo, Gitea https://mylogin.world.compas.cs.stonybrook.edu/integrations/gitea, GitLab https://mylogin.world.compas.cs.stonybrook.edu/integrations/gitlab, Grafana https://mylogin.world.compas.cs.stonybrook.edu/integrations/grafana, Harbor https://mylogin.world.compas.cs.stonybrook.edu/integrations/harbor, Immich https://mylogin.world.compas.cs.stonybrook.edu/integrations/immich, Jellyfin https://mylogin.world.compas.cs.stonybrook.edu/integrations/jellyfin, Mealie https://mylogin.world.compas.cs.stonybrook.edu/integrations/mealie, Nextcloud https://mylogin.world.compas.cs.stonybrook.edu/integrations/nextcloud, Outline https://mylogin.world.compas.cs.stonybrook.edu/integrations/outline, Paperless-ngx https://mylogin.world.compas.cs.stonybrook.edu/integrations/paperless, Proxmox Backup Server https://mylogin.world.compas.cs.stonybrook.edu/integrations/pbs, Portainer https://mylogin.world.compas.cs.stonybrook.edu/integrations/portainer, Vaultwarden https://mylogin.world.compas.cs.stonybrook.edu/integrations/vaultwarden, Wiki.js https://mylogin.world.compas.cs.stonybrook.edu/integrations/wikijs. Source: https://github.com/mferdman/mylogin.world-clients. Rules: do not implement passwords, do not add an OAuth callback on the app's own URL, do not store provider tokens. # Relay protocol The relay gives a service a public HTTPS origin for OAuth redirects and WebAuthn ceremonies. It stores nothing about users and verifies nothing; the service does. There are no credentials: a service is identified by its slug (the first label of its sign-in address `https://.login.mylogin.world.compas.cs.stonybrook.edu`; clients treat it as opaque), and the only thing a transaction can do is send the browser back to the app URL configured for that service in the dashboard. Base URL: `https://api.mylogin.world.compas.cs.stonybrook.edu`. The same API is served under `/v1/` on every sign-in host. Errors: `{ error: { code, message, request_id } }`. ## Providers `GET /v1/providers` → list of `{ id, name, kind: 'oidc'|'oauth2', managed, managed_client_id?, authorization_endpoint, token_endpoint, issuer?, jwks_uri?, userinfo_endpoint?, scopes, color, icon, byo_fields }`. It is the live catalogue: `color` and `icon` (full-colour SVG) are for drawing buttons, and `byo_fields` lists what a customer's own client needs (`client_id`, `client_secret`, `issuer`, `team_id`, `key_id`, `private_key`). `managed` means the relay holds its own client for that provider. ## Transactions `POST /v1/services//transactions` ```json { "ttl_sec": 300, "message": "optional line shown on the page", "return_url": "https://192.168.1.20/private", "methods": [ { "type": "oauth", "provider": "google", "mode": "byo", "state": "", "authorize_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=&response_type=code&scope=openid%20email%20profile&state=&nonce=&code_challenge=...&code_challenge_method=S256" }, { "type": "oauth", "provider": "github", "mode": "managed", "state": "", "nonce": "" }, { "type": "passkey", "action": "authenticate", "options": { "...PublicKeyCredentialRequestOptionsJSON with rpId = the sign-in address hostname..." } } ] } ``` → `{ id, browser_url, expires_at }`. Send the browser to `browser_url`. Keep `id` on the server: it is the secret that collects the result, and it never appears in the browser URL. `id` and the page token in `browser_url` are opaque strings; do not parse them. Rules: `state` values unique per transaction and 16-128 characters; BYO `authorize_url` must be https and, for known providers, on that provider's authorization host; `ttl_sec` ≤ 600; `return_url` must be on the service's configured app URL origin, otherwise the app URL itself is used. A service with no app URL cannot create transactions (`app_url_missing`). `GET /v1/transactions/` → `{ status: 'pending', retry_after }` | `{ status: 'completed', method: , result }` | `{ status: 'consumed' | 'cancelled' | 'expired' }`. A completed result is returned once; the row is then `consumed` and the payload deleted. That delivery ends the transaction: nothing further is required from the service, and it is what the dashboard counts as a sign-in. `result`: - BYO OAuth: `{ type:'oauth', mode:'byo', provider, state, code }`. Exchange `code` at the provider's `token_endpoint` with your client and PKCE verifier; verify the ID token (issuer, audience = your client id, nonce, signature via `jwks_uri`) or fetch `userinfo_endpoint` for `oauth2` providers. - Managed OAuth: `{ type:'oauth', mode:'managed', provider, state, id_token?, access_token?, token_type? }`. Verify `id_token` with audience = `managed_client_id` and your `nonce`; for `oauth2` providers call `userinfo_endpoint` with `access_token`. The relay discards tokens after delivery. - Passkey: `{ type:'passkey', action, response }` — the raw `RegistrationResponseJSON` or `AuthenticationResponseJSON`. Verify with a WebAuthn library using the sign-in address as expected origin, its hostname as RP ID, and your stored challenge and credential public keys. The browser page offers Cancel (transaction → `cancelled`, browser → return URL) and expires with the transaction. After completion the browser is redirected to the return URL. ## Custom domains A service may add one custom hostname (`CNAME auth.example.com → .login.mylogin.world.compas.cs.stonybrook.edu`; a zone apex uses A records to the sites' IPs, which do not follow failover). The slug address keeps working; the host a transaction is created for is the host its page uses: `POST /v1/services//transactions` (a path segment containing a dot is a hostname) returns a `browser_url` on `https://`. On a custom host: - managed providers work as on the slug address: their callback stays `https://login.mylogin.world.compas.cs.stonybrook.edu/oauth/cb`, which returns the browser to the page on the hostname, and the consent screen names the relay; - your own OAuth clients register `https:///oauth/cb`; - passkeys use the hostname as RP ID and origin, so passkeys made on the slug address do not work there, nor the reverse. The SDK takes the host from `AUTH_RELAY_URL=https://`. ## What the relay never does Store identities, credentials, or tokens beyond delivery; decide who may sign in; connect to the service; verify a login on the service's behalf; send the browser anywhere except the service's configured app URL.