Skip to content

Quickstart

Create an app, give it a key, and sign a person in with an emailed link. You need a terminal and a site you can run locally.

1. Create an account and an app

Sign in at app.dianthan.com with your email. You don't set a password. Then create your first app from the CLI:

Terminal
npx dianthan login
npx dianthan apps create "Field Notes" --domain fieldnotes.localhost --signup open

The domain tells Dianthan where sign-in links may send people back to. --signup open lets anyone who signs in become a customer of this app; leave it off to allow invited people only.

Use <name>.localhost for local development. Browsers resolve it to your own machine, and unlike plain localhost, it gives each app a domain of its own.

2. Create a server key

Terminal
npx dianthan keys create --app fieldnotes --name web-server
Text
DIANTHAN_URL=https://api.dianthan.com
DIANTHAN_APP_ID=app_8Jq2…
DIANTHAN_KEY=dn_live_4f9c…

The key is shown once. Put these three lines in your site's server environment (for example .env.local). Never send the key to a browser; it can act for any user of the app.

From your server, ask Dianthan to email a link:

Terminal
curl https://api.dianthan.com/v1/auth/magic-link \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@example.com",
    "app_id": "app_8Jq2…",
    "return_to": "http://fieldnotes.localhost:3000/auth/callback"
  }'

The response is always 202, whether or not the address has an account, so the endpoint can't be used to find out who your users are.

4. Exchange the grant

When Ada clicks the link, she confirms on a Dianthan page and lands on your return_to URL with a single-use grant parameter. Your callback route exchanges it for a session:

app/auth/callback/route.ts
export async function GET(req: Request) {
  const grant = new URL(req.url).searchParams.get("grant");
  const res = await fetch(`${process.env.DIANTHAN_URL}/v1/auth/grants/exchange`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ grant }),
  });
  const session = await res.json();
  // session.access_token (short-lived JWT), session.refresh_token (opaque)

  const out = Response.redirect(new URL("/", req.url));
  out.headers.append("Set-Cookie", `dn_refresh=${session.refresh_token}; HttpOnly; Secure; SameSite=Lax; Path=/`);
  return out;
}

Grants last a few minutes and work once. Store the refresh token in an httpOnly cookie on your own domain. Keep the access token in memory or in a short-lived cookie, and refresh it with POST /v1/auth/refresh.

5. Ask who is signed in

Terminal
curl https://api.dianthan.com/v1/me \
  -H "Authorization: Bearer $ACCESS_TOKEN"
JSON
{
  "id": "usr_x81…",
  "email": "ada@example.com",
  "name": null
}

That's a working sign-in. From here:

  • Add Google and GitHub sign-in in Identity.
  • Put a feature behind a plan with Billing.
  • Record what people do with Observe.