Skip to content

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.

Terminal
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_to must 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 202 whether 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

Terminal
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:

TokenLifetimeKeep it
access_tokenMinutesIn memory or a short-lived cookie. Send as Authorization: Bearer.
refresh_tokenDaysIn 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:

Terminal
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

Terminal
# 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.