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).
bashcurl -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.
javascriptconst 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.
javascriptconst 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:
| Header | Description | Required |
|---|
Content-Type | Always application/json | Yes |
Authorization | Bearer token for authenticated endpoints | Conditional |
X-Client-ID | Your service identifier (slug) — enables per-service scoping | Recommended |
Register
Create a new user account. Returns a JWT and refresh token.
Request body
| Field | Type | Description |
|---|
email | string | User's email address |
password | string | Password (8+ chars, uppercase, lowercase, number) |
name | string | Display name (optional) |
invite_code | string | Invite code (required if invite_only mode) |
javascriptconst 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
Authenticate a user and return a JWT and refresh token.
Request body
| Field | Type | Description |
|---|
email | string | Email address |
password | string | Password |
javascriptconst { access_token, refresh_token } = 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 })
}).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
Returns the authenticated user's profile, including their service access.
javascriptconst 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
Exchange a refresh token for a new access_token/refresh_token pair.
javascriptconst { 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
Revokes the session and refresh token. Send both tokens for a complete logout.
javascriptawait 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.
callbackhttps://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:
| Provider | Scopes | Description |
|---|
| Google | email profile openid | Email, profile, and OpenID identifier |
| GitHub | user:email read:user | User email and profile |
JWT tokens issued by Idey use the HS256 algorithm. Here is the payload structure:
jwt payload{
"sub": "550e8400-...",
"email": "user@example.com",
"name": "John Doe",
"roles": ["user"],
"iss": "idey",
"aud": "idey",
"services": [
{ "sid": "my-app", "r": "member" }
],
"iat": 1709136000,
"exp": 1709139600
}
| Claim | Type | Description |
|---|
sub | string | Unique user identifier (UUID) |
email | string | User's email address |
name | string | Display name |
roles | string[] | Global roles (user, admin) |
services | array | Per-service access: sid (service ID) and r (role) |
iss | string | Token issuer (always 'idey') |
exp | number | Expiration 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.jsconst jwt = require('jsonwebtoken');
function verifyIdeyToken(token, jwtSecret) {
try {
const payload = jwt.verify(token, jwtSecret, {
issuer: 'idey',
audience: 'idey'
});
return payload;
} catch (err) {
return null;
}
}
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.
| Mode | Description | Registration |
|---|
public | Anyone can register | Automatic on login |
invite_only | Registration by invitation only | With invite code |
allowlist | Registration limited to allowed emails | If email in list |
In public mode, access is automatically provisioned on first login. Use the checkServiceAccess endpoint to verify a user's access.
javascriptconst 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:
| Role | Description |
|---|
owner | Service owner — full control |
admin | Administrator — user management and configuration |
member | Member — standard access to features |
viewer | Viewer — 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.