API Documentation

Integrate Idey into your application in minutes.

Quick Start

Three steps to authenticate your users with Idey.

1Register your application

Create a service in Idey to get a client identifier (slug).

bash
curl -X POST https://idey.org/api/auth/services/register \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <admin_token>" \
  -d '{"name": "My App", "slug": "my-app", "redirect_uris": ["https://myapp.com/callback"]}'

2Authenticate a user

Call the login endpoint with the user's credentials.

javascript
const response = await fetch('https://idey.org/api/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Client-ID': 'my-app'
  },
  body: JSON.stringify({ email, password })
});
const { access_token, refresh_token, service_role } = await response.json();

3Use the token

Pass the JWT token in the Authorization header to access protected resources.

javascript
const user = await fetch('https://idey.org/api/auth/me', {
  headers: { 'Authorization': `Bearer ${access_token}` }
}).then(r => r.json());
The X-Client-ID header is recommended to receive the service_role in the response and enrich the JWT with your service's access data.

Base URL & Headers

All endpoints use the same base URL:

https://idey.org/api/auth

Common headers for all requests:

HeaderDescriptionRequired
Content-TypeAlways application/jsonYes
AuthorizationBearer token for authenticated endpointsConditional
X-Client-IDYour service identifier (slug) — enables per-service scopingRecommended

Register

POST/api/auth/register

Create a new user account. Returns a JWT and refresh token.

Request body

FieldTypeDescription
emailstringUser's email address
passwordstringPassword (8+ chars, uppercase, lowercase, number)
namestringDisplay name (optional)
invite_codestringInvite code (required if invite_only mode)
javascript
const response = await fetch('https://idey.org/api/auth/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'user@example.com',
    password: 'SecurePass123',
    name: 'John Doe'
  })
});
response
{
  "success": true,
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "name": "John Doe"
  },
  "access_token": "eyJhbG...",
  "refresh_token": "rt_abc123..."
}

Login

POST/api/auth/login

Authenticate a user and return a JWT and refresh token.

Request body

FieldTypeDescription
emailstringEmail address
passwordstringPassword
javascript
const { access_token, refresh_token } = await fetch('https://idey.org/api/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Client-ID': 'my-app' // optional: get service_role in response
  },
  body: JSON.stringify({ email, password })
}).then(r => r.json());
2FA: If the user has 2FA (TOTP) enabled, the response will contain totp_required: true with a totp_token. Then call /api/auth/totp/verify with the TOTP code.

User Profile

GET/api/auth/me

Returns the authenticated user's profile, including their service access.

javascript
const user = await fetch('https://idey.org/api/auth/me', {
  headers: { 'Authorization': `Bearer ${access_token}` }
}).then(r => r.json());
response
{
  "success": true,
  "user": {
    "id": "550e8400-...",
    "email": "user@example.com",
    "name": "John Doe",
    "roles": ["user"],
    "email_verified": true
  },
  "services": [
    { "service_id": "my-app", "role": "member", "status": "active" }
  ]
}

Refresh Token

POST/api/auth/refresh

Exchange a refresh token for a new access_token/refresh_token pair.

javascript
const { access_token, refresh_token: new_refresh } = await fetch(
  'https://idey.org/api/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refresh_token })
  }
).then(r => r.json());
Each refresh token is single-use. After use, it is revoked and a new one is issued. Always store the latest refresh_token received.

Logout

POST/api/auth/logout

Revokes the session and refresh token. Send both tokens for a complete logout.

javascript
await fetch('https://idey.org/api/auth/logout', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${access_token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ refresh_token })
});

OAuth Integration

Idey supports Google and GitHub as OAuth providers. The flow is a simple three-step process.

1Redirect to Idey

Create a link to Idey's OAuth endpoint with your client_id and redirect_uri.

html
<a href="https://idey.org/api/auth/oauth?provider=google
  &client_id=my-app
  &redirect_uri=https://myapp.com/callback">
  Sign in with Google
</a>

2Receive the callback

After authentication, Idey redirects to your redirect_uri with tokens in the parameters.

callback
// Idey redirects to your callback with:
https://myapp.com/callback?
  access_token=eyJhbG...
  &refresh_token=rt_abc...
  &service_role=member

3Use the tokens

Store the tokens and use the access_token for authenticated API calls.

OAuth Scopes

Scopes requested by Idey from OAuth providers:

ProviderScopesDescription
Googleemail profile openidEmail, profile, and OpenID identifier
GitHubuser:email read:userUser email and profile

JWT Format

JWT tokens issued by Idey use the HS256 algorithm. Here is the payload structure:

jwt payload
{
  "sub": "550e8400-...",        // User ID
  "email": "user@example.com", // User email
  "name": "John Doe",          // Display name
  "roles": ["user"],           // Global roles
  "iss": "idey",               // Issuer
  "aud": "idey",               // Audience
  "services": [               // Per-service access
    { "sid": "my-app", "r": "member" }
  ],
  "iat": 1709136000,           // Issued at
  "exp": 1709139600            // Expires (1h)
}
ClaimTypeDescription
substringUnique user identifier (UUID)
emailstringUser's email address
namestringDisplay name
rolesstring[]Global roles (user, admin)
servicesarrayPer-service access: sid (service ID) and r (role)
issstringToken issuer (always 'idey')
expnumberExpiration timestamp (1 hour after issuance)

The access token expires after 1 hour. The refresh token expires after 7 days and is single-use (automatic rotation).

Token Verification

Verify tokens server-side with the jsonwebtoken library and your shared JWT secret:

node.js
const jwt = require('jsonwebtoken');
function verifyIdeyToken(token, jwtSecret) {
  try {
    const payload = jwt.verify(token, jwtSecret, {
      issuer: 'idey',
      audience: 'idey'
    });
    return payload;
  } catch (err) {
    return null; // Invalid or expired token
  }
}
The JWT secret is shared when registering your service. Never expose it client-side.

Service Access Modes

Each service registered in Idey can configure its access mode to control who can register.

ModeDescriptionRegistration
publicAnyone can registerAutomatic on login
invite_onlyRegistration by invitation onlyWith invite code
allowlistRegistration limited to allowed emailsIf email in list

In public mode, access is automatically provisioned on first login. Use the checkServiceAccess endpoint to verify a user's access.

javascript
// Check access before login
const access = await fetch('https://idey.org/api/auth/service-access/check', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ service_id: 'my-app' })
}).then(r => r.json());

Per-Service Roles

Each user has a specific role in each service they have access to:

RoleDescription
ownerService owner — full control
adminAdministrator — user management and configuration
memberMember — standard access to features
viewerViewer — read-only access

The role is included in the JWT (services claim) and in the login response (service_role field) when X-Client-ID is sent.