> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nemu.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Sign a user in and read their profile using the official SDK

This walks through a full login. A user approves your app, your app receives a token, and
your app reads the profile of the user who approved access.

## Prerequisites

<Steps>
  <Step title="Register a Web application">
    Create a Web application in the console and add a redirect URI, for example
    `https://your.app/callback`. See [Register an application](/oauth#register-an-application).
  </Step>

  <Step title="Grant the profile scope">
    Add the `profile:read` scope so your app can read the user's account.
  </Step>

  <Step title="Install the SDK">
    <CodeGroup>
      ```bash npm theme={null}
      npm install @nemu-ai/sdk
      ```

      ```bash bun theme={null}
      bun add @nemu-ai/sdk
      ```
    </CodeGroup>
  </Step>
</Steps>

## Send the user to the consent page

Build an authorize URL and redirect the user to it. The SDK generates the PKCE values for
you. Keep `code_verifier` and `state` for the callback.

```ts login.ts theme={null}
import { NemuOAuth } from "@nemu-ai/sdk";

const oauth = new NemuOAuth({
  client_id: process.env.nemu_client_id!,
  client_secret: process.env.nemu_client_secret!,
  redirect_uri: "https://your.app/callback",
});

const { url, code_verifier, state } = oauth.authorize_url({
  scopes: ["profile:read", "workspaces:read"],
  state: "a_random_value",
});

save_to_session({ code_verifier, state });
redirect(url);
```

The user lands on the consent screen, sees the scopes you asked for, and approves. We then
redirect back to your `redirect_uri` with a short lived `code` and the `state` you sent.

## Handle the callback

Verify the `state`, then exchange the `code` for tokens. `exchange_code` returns a ready to
use client that acts as the user.

```ts callback.ts theme={null}
import { NemuOAuth } from "@nemu-ai/sdk";

const oauth = new NemuOAuth({
  client_id: process.env.nemu_client_id!,
  client_secret: process.env.nemu_client_secret!,
  redirect_uri: "https://your.app/callback",
});

const { code_verifier, state } = load_from_session();
if (query.state !== state) throw new Error("state_mismatch");

const nemu = await oauth.exchange_code({
  code: query.code,
  code_verifier,
});

const user = await nemu.user.get();
console.log(user.email, user.id, user.plan);
```

<Check>
  `nemu.user.get()` returns the user who approved access. This is the answer to "who clicked
  Authorize".
</Check>

## Keep the session

`exchange_code` accepts an `on_refresh` callback so you can persist rotated tokens. Restore a
client later with `from_tokens`.

```ts theme={null}
const nemu = await oauth.exchange_code({
  code: query.code,
  code_verifier,
  on_refresh: (tokens) => save_tokens(user_id, tokens),
});

const restored = oauth.from_tokens(load_tokens(user_id), (tokens) =>
  save_tokens(user_id, tokens),
);
```

## Next steps

<CardGroup cols={2}>
  <Card title="Authorization code" href="/oauth/authorization_code">
    The raw HTTP behind the SDK, including PKCE and error handling.
  </Card>

  <Card title="Scopes" href="/oauth/scopes">
    Everything you can request beyond the profile.
  </Card>
</CardGroup>
