Identity
Passwordless sign-in, sessions, organizations, roles, single sign-on and two-factor authentication. There are no passwords anywhere in Dianthan, so there is nothing to hash, reset or leak.
Sign-in with an emailed link
curl https://api.dianthan.com/v1/auth/magic-link \
-H "Content-Type: application/json" \
-d '{"email":"ada@example.com","app_id":"app_…","return_to":"https://fieldnotes.app/auth/callback"}'return_tomust be on a domain registered to the app. Any other URL is refused.- Links last 15 minutes and work once.
- The link opens a confirmation page first, so the security scanners in mail clients that open every link can't use it up.
- The response is
202whether or not the address is known.
After confirmation, the person lands on return_to?grant=…. Exchange the grant from your server with POST /v1/auth/grants/exchange, as shown in the Quickstart.
Sign-in with Google or GitHub
curl "https://api.dianthan.com/v1/auth/oauth/google?app_id=app_…&return_to=https://fieldnotes.app/auth/callback"The response contains the provider URL. Redirect the browser to it. The person comes back to return_to with a grant, exactly as with an emailed link, so one callback route handles both.
Accounts are matched by verified email: someone who signed in with a link and later uses Google with the same address is the same user.
Sessions
An exchange returns two tokens:
| Token | Lifetime | Keep it |
|---|---|---|
access_token | Minutes | In memory or a short-lived cookie. Send as Authorization: Bearer. |
refresh_token | Days | In an httpOnly, Secure cookie on your own domain. |
Refresh with POST /v1/auth/refresh. The refresh token rotates each time, and reusing an old one revokes the session. List sessions with GET /v1/auth/sessions and revoke one with DELETE /v1/auth/sessions/:id, or all of them with DELETE /v1/auth/sessions.
Creating users from your server
When your own sign-up flow already knows a person, create them directly with your app key:
curl https://api.dianthan.com/v1/auth/register \
-H "X-API-Key: dn_live_…" -H "X-App-Id: app_…" \
-H "Content-Type: application/json" \
-d '{"email":"jane@customer.com","name":"Jane"}'Organizations and roles
# Create a team
curl -X POST https://api.dianthan.com/v1/organizations \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Acme"}'
# Invite someone
curl -X POST https://api.dianthan.com/v1/organizations/org_…/invitations \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"email":"grace@acme.com","role":"member"}'Invitations are accepted with POST /v1/invitations/:id/accept. Define custom roles with POST /v1/organizations/:id/roles and attach permissions from GET /v1/permissions.
Two-factor authentication and step-up
People can add an authenticator app with POST /v1/me/mfa/totp/setup and confirm it with /verify. They get ten recovery codes, each usable once.
For sensitive actions such as deleting an organization or changing a payout account, ask for a fresh check with POST /v1/auth/step-up. The access token it returns carries a recent-authentication claim that your server can require.
Single sign-on
Organizations can sign in through their own identity provider. Create a connection with POST /v1/organizations/:id/sso, then send members to GET /v1/auth/sso/:connection_id/start. Members of that organization can then be required to use it.
In preview: passkeys, as a third way to sign in alongside links and OAuth.