Auth is the second piece of the MIOSA managed-data experience. When a project is created, MIOSA provisions a per-project auth service. The app gets two env vars:
AUTH_URL=https://auth.miosa.app/proj_xxx
AUTH_JWT_SECRET=<random 64-char hex> The generated app uses them like this:
// Sign up a new end user
const res = await fetch(`${process.env.AUTH_URL}/signup`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
})
const { access_token, user } = await res.json()
// Verify a JWT in the app's own API
import jwt from "jsonwebtoken"
const claims = jwt.verify(token, process.env.AUTH_JWT_SECRET!)
const userId = claims.sub That’s the agent-on-day-zero experience: agent writes a signup flow on day zero, never has to ask the user to configure auth.
What’s offered
| Feature | Status |
|---|---|
| Email + password signup / login | Planned |
| Magic links | Planned |
| OAuth providers (Google, GitHub) | Planned |
| Password reset | Planned |
| Email verification | Planned |
| JWT access + refresh tokens | Planned |
| MFA / TOTP | Coming soon |
| Passkeys / WebAuthn | Coming soon |
| Enterprise SSO (SAML, OIDC) | Coming soon |
Endpoints
POST {AUTH_URL}/signup
POST {AUTH_URL}/token (login)
POST {AUTH_URL}/refresh
POST {AUTH_URL}/logout
POST {AUTH_URL}/reset
GET {AUTH_URL}/user (current user, requires Bearer)
PATCH {AUTH_URL}/user End users are not MIOSA users
Important distinction:
- MIOSA platform user = the developer / platform builder. Authenticates with
msk_*API keys or JWT sessions issued by MIOSA. Has access to the MIOSA dashboard. - End user of a generated app = the visitor to an app YOUR PLATFORM built (e.g. Dr. Smith logging into a dental clinic site). Authenticates against the per-project
AUTH_URL. Has no MIOSA account.
These are completely separate auth systems. The same email can be a MIOSA platform user AND an end user of someone’s app; they’re different records, with different password hashes.
Per-project isolation
Each project gets its own user table. Users from proj_smile_dental cannot log into proj_smile_clinic. The JWT secret is per-project; you cannot use one project’s token to authenticate against another.
This makes the “user signs up to the dental clinic site” pattern safe even when the same MIOSA tenant hosts thousands of independent end-user apps.
Row-level security (Postgres pattern)
When combined with managed Postgres, the auth JWT carries the user ID (sub claim). Your runtime code uses it for row-level filtering:
const claims = jwt.verify(token, process.env.AUTH_JWT_SECRET!)
const appointments = await pool.query(
"SELECT * FROM appointments WHERE patient_id = $1",
[claims.sub]
) Or use Postgres RLS policies if your Postgres has them enabled:
ALTER TABLE appointments ENABLE ROW LEVEL SECURITY;
CREATE POLICY appointment_owner ON appointments
USING (patient_id = current_setting('jwt.claims.sub')::uuid); Custom domains for auth
If you want the auth URLs to be branded (auth.smiledental.test instead of auth.miosa.app), add a custom domain to the project’s auth service. Same flow as Deployment Domains, different target.
Bring your own auth?
Yes. Skip the managed auth, set your own AUTH_URL and AUTH_JWT_SECRET to point at Clerk / Auth0 / your own service. MIOSA’s runtime injects whatever you set.
Python SDK
See also
- Overview — the broader data plane
- Postgres — pairs naturally with auth for RLS
- Platform / Browser Tokens — for MIOSA-level browser access; distinct from your app’s end-user auth