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

# Authentication

> Send a bearer token with every request. Get one with OAuth 2.1 and PKCE, the same flow MCP clients use.

Endpoints that touch your data need an `Authorization` header:

```bash theme={null}
curl https://api.nebyoulous.space/me \
  -H "Authorization: Bearer $NEBYOULOUS_TOKEN"
```

Each endpoint page shows whether a token is required, optional, or not used.
Public endpoints such as `GET /public/posts` and `GET /health` work without
one. Optional-auth endpoints return extra data to the owner.

## Get a token

The API accepts access tokens from any Nebyoulous sign-in: the web session,
`nebyoulous login`, or an OAuth grant. For your own scripts, use OAuth. It's
standard OAuth 2.1 with the authorization code flow, PKCE (`S256`), and
dynamic client registration. Clients are public, so there's no client secret.

**1. Register a client**

Register once and keep the `client_id`. Any redirect URI works. A local one
is easiest for scripts.

```bash theme={null}
curl -s https://api.nebyoulous.space/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My stacking script",
    "redirect_uris": ["http://127.0.0.1:8765/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "token_endpoint_auth_method": "none"
  }'
```

**2. Make a PKCE pair**

```bash theme={null}
VERIFIER=$(openssl rand -base64 48 | tr -d '=+/\n' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary \
  | openssl base64 | tr '+/' '-_' | tr -d '=\n')
```

**3. Approve in the browser**

Open this URL, replacing `CLIENT_ID` and `CHALLENGE`:

```text theme={null}
https://api.nebyoulous.space/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A8765%2Fcallback&code_challenge=CHALLENGE&code_challenge_method=S256&state=xyz
```

Sign in, pick how long the token should last (7, 30, or 90 days), and
choose **Allow access**. The browser goes to your redirect URI with
`?code=...&state=xyz`. If nothing is listening there, copy `code` from the
address bar. Codes expire after 5 minutes.

**4. Trade the code for tokens**

```bash theme={null}
curl -s https://api.nebyoulous.space/oauth/token \
  -d grant_type=authorization_code \
  -d code=CODE \
  -d redirect_uri=http://127.0.0.1:8765/callback \
  -d client_id=CLIENT_ID \
  -d code_verifier="$VERIFIER"
```

The response has `access_token`, `refresh_token`, and `expires_in` in
seconds. The token endpoint takes form-encoded bodies, not JSON.

## Refresh

Both tokens last as long as you chose on the approval page. Refreshing issues
a new pair and retires the old refresh token:

```bash theme={null}
curl -s https://api.nebyoulous.space/oauth/token \
  -d grant_type=refresh_token \
  -d refresh_token=REFRESH_TOKEN \
  -d client_id=CLIENT_ID
```

## Discovery

Libraries that implement OAuth discovery can start from the metadata
documents instead of these URLs:

| | |
| - | - |
| Authorization server metadata (RFC 8414) | `GET /.well-known/oauth-authorization-server` |
| Protected resource metadata (RFC 9728) | `GET /.well-known/oauth-protected-resource/mcp` |

## Errors

| Status | `code` | What to do |
| - | - | - |
| `401` | `UNAUTHORIZED` | The token is missing, malformed, or expired. Refresh it or sign in again. |
| `403` | `PENDING_APPROVAL` | Your account is waiting for an admin. Every authenticated endpoint answers this way until approval. |
| `403` | `FORBIDDEN` | A few actions, such as approving a CLI or OAuth sign-in, only work from the web app. |

> [!WARNING]
>
> An access token can do anything you can do in the web app. Keep it out of
> source control and logs. There's no way to revoke one from the web app yet,
> so pick the shortest lifetime that works for your script.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.