API Reference
Complete API reference for GrydAuth endpoints.
Base URL
https://your-api.com/apiAuthentication
Most endpoints require authentication via Bearer token:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...Auth Endpoints
Login
Authenticate a user and obtain tokens.
POST /api/auth/loginHeaders:
| Header | Required | Description |
|---|---|---|
X-App-Id | No | Application ID for app-specific access validation |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email |
password | string | Yes | User password |
isPasswordEncrypted | boolean | No | If true, password is already encrypted (default: true) |
preferredTenantId | guid | No | Preferred tenant for multi-tenant login |
requestedAppId | string | No | Set automatically from X-App-Id header |
Example:
{
"email": "user@example.com",
"password": "Password123!",
"isPasswordEncrypted": false,
"preferredTenantId": "550e8400-e29b-41d4-a716-446655440001"
}Response (200):
{
"isSuccess": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2g...",
"expiresAt": "2026-01-29T13:00:00Z",
"permissions": ["read:products", "update:products"],
"isFirstLogin": false,
"mustChangePassword": false,
"daysUntilPasswordExpiration": null,
"isGlobal": false,
"requiresTenantSelection": false,
"tokenType": "Tenant",
"currentTenant": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Acme Corp",
"isDefault": true,
"permissions": ["read:products"]
},
"smartAutoSwitched": true
}
}Multi-Tenant Login Flow
When isGlobal: true and requiresTenantSelection: true:
- User has access to multiple tenants
- Token is a Global Token (2 minutes TTL, restricted access)
- Use
POST /api/auth/switch-tenantto select a tenant - Receive a full Tenant Token (60 minutes TTL)
Error Responses:
| Status | Code | Description |
|---|---|---|
| 401 | INVALID_CREDENTIALS | Invalid email or password |
| 401 | ACCOUNT_LOCKED | Account locked |
| 401 | ACCOUNT_DISABLED | Account disabled |
| 401 | EMAIL_NOT_CONFIRMED | Email not confirmed |
Social Login
Authenticate using a social provider (Auth0, Google, etc.).
POST /api/auth/social-loginHeaders:
| Header | Required | Description |
|---|---|---|
X-App-Id | No | Application ID for app-specific access validation |
Request Body:
{
"provider": "google",
"accessToken": "ya29.a0AfH6SM...",
"preferredTenantId": "550e8400-e29b-41d4-a716-446655440001"
}Register
Create a new user account.
POST /api/auth/registerRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User email |
password | string | Yes | Password (min 8 chars) |
fullName | string | Yes | Full name |
phoneNumber | string | No | Phone number |
Response (201):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"email": "newuser@example.com",
"fullName": "Jane Doe",
"createdAt": "2026-01-29T12:00:00Z"
}
}Refresh Token
Exchange refresh token for new tokens.
POST /api/auth/refreshRequest Body:
| Field | Type | Required | Description |
|---|---|---|---|
refreshToken | string | Yes | The refresh token from login |
tenantId | guid | No | Target tenant ID (for tenant switching during refresh) |
{
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2g..."
}Response (200):
{
"isSuccess": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "bmV3IHJlZnJlc2ggdG9rZW4...",
"expiresAt": "2026-01-29T14:00:00Z",
"permissions": ["read:products"],
"isGlobal": false,
"tokenType": "Tenant"
}
}Logout
Invalidate current session and all user tokens.
POST /api/auth/logout
Authorization: Bearer {token}Simplified OAuth 2.0 Logout
GrydAuth follows OAuth 2.0 RFC 7009 best practices:
- No request body required - All info extracted from Authorization header
- Global logout only - Invalidates ALL user sessions using timestamp-based blacklist
- Secure by design - Doesn't expose refresh token in requests
Response (200):
{
"isSuccess": true,
"message": "Logged out successfully"
}Switch Tenant
Switch to a different tenant context. Works with both Global Tokens (first-time selection) and Tenant Tokens (switching between tenants).
POST /api/auth/switch-tenant
Authorization: Bearer {token}Request Body:
{
"tenantId": "550e8400-e29b-41d4-a716-446655440002"
}Response (200):
{
"isSuccess": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "bmV3IHJlZnJlc2ggdG9rZW4...",
"expiresAt": "2026-01-29T14:00:00Z",
"isGlobal": false,
"tokenType": "Tenant",
"currentTenant": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "New Tenant",
"isDefault": false
}
}
}Get Current User
Get authenticated user information.
GET /api/auth/me
Authorization: Bearer {token}Query Parameters:
| Parameter | Type | Description |
|---|---|---|
include | string | Use profile for complete user data from database |
Response (200) - Basic (from JWT token, no DB access):
{
"isSuccess": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Doe",
"email": "user@example.com",
"roles": ["User", "Manager"],
"permissions": ["read:products", "update:products"]
}
}Response (200) - With ?include=profile (from database, cached 30min):
{
"isSuccess": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"fullName": "John Doe",
"phoneNumber": "+1234567890",
"profilePictureUrl": "https://...",
"emailConfirmed": true,
"roles": ["User", "Manager"],
"permissions": ["read:products", "update:products"],
"tenants": [
{
"id": "tenant-1",
"name": "Acme Corp",
"isDefault": true
}
],
"createdAt": "2026-01-01T00:00:00Z",
"lastLoginAt": "2026-01-29T10:00:00Z"
}
}Get Complete User Profile
Alias for GET /api/auth/me?include=profile. Returns complete user data.
GET /api/auth/me/complete
Authorization: Bearer {token}Request Password Reset
Request a password reset email.
POST /api/auth/request-password-resetRequest Body:
{
"email": "user@example.com"
}Reset Password
Complete password reset with token from email.
POST /api/auth/reset-passwordRequest Body:
{
"email": "user@example.com",
"token": "reset-token-from-email",
"newPassword": "NewPassword789!"
}Users Endpoints
Note on User Endpoints
The current user info is now available via GET /api/auth/me. The /api/users endpoints are for administrative user management.
List Users (Admin)
GET /api/users
Authorization: Bearer {admin-token}Required Permission: read:users
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page | int | Page number (default: 1) |
pageSize | int | Items per page (default: 20, max: 100) |
search | string | Search by name or email |
role | string | Filter by role |
isActive | bool | Filter by status |
sortBy | string | Sort field |
sortDirection | string | asc or desc |
Response (200):
{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"fullName": "John Doe",
"roles": ["User"],
"isActive": true,
"createdAt": "2026-01-01T00:00:00Z"
}
],
"totalCount": 150,
"page": 1,
"pageSize": 20,
"totalPages": 8
}Get User by ID (Admin)
GET /api/users/{id}
Authorization: Bearer {admin-token}Required Permission: read:users
Create User (Admin)
POST /api/users
Authorization: Bearer {admin-token}Required Permission: create:users
Request Body:
{
"email": "newuser@example.com",
"password": "TempPassword123!",
"fullName": "New User",
"roles": ["User"],
"sendWelcomeEmail": true
}Update User (Admin)
PUT /api/users/{id}
Authorization: Bearer {admin-token}Required Permission: update:users
Delete User (Admin)
DELETE /api/users/{id}
Authorization: Bearer {admin-token}Required Permission: delete:users
Roles Endpoints
List Roles
GET /api/roles
Authorization: Bearer {admin-token}Required Permission: read:roles
Response (200):
{
"items": [
{
"id": "role-1",
"name": "Admin",
"description": "Administrator role",
"permissions": ["*"],
"userCount": 5
},
{
"id": "role-2",
"name": "User",
"description": "Standard user",
"permissions": ["read:products"],
"userCount": 150
}
]
}Create Role
POST /api/roles
Authorization: Bearer {admin-token}Required Permission: create:roles
Request Body:
{
"name": "Manager",
"description": "Department manager",
"permissions": [
"read:products",
"create:products",
"update:products",
"read:reports"
]
}Update Role
PUT /api/roles/{id}
Authorization: Bearer {admin-token}Required Permission: update:roles
Delete Role
DELETE /api/roles/{id}
Authorization: Bearer {admin-token}Required Permission: delete:roles
Assign Role to User
POST /api/users/{userId}/roles
Authorization: Bearer {admin-token}Required Permission: update:users
Request Body:
{
"roleNames": ["Manager", "User"]
}Permissions Endpoints
List Permissions
GET /api/permissions
Authorization: Bearer {admin-token}Required Permission: read:permissions
Response (200):
{
"items": [
{
"id": "perm-1",
"name": "create:products",
"description": "Create new products",
"category": "Products"
},
{
"id": "perm-2",
"name": "read:products",
"description": "View products",
"category": "Products"
}
]
}Create Permission
POST /api/permissions
Authorization: Bearer {admin-token}Required Permission: create:permissions
Request Body:
{
"name": "export:reports",
"description": "Export reports to PDF/Excel",
"category": "Reports"
}Tenants Endpoints
List Tenants (Super Admin)
GET /api/tenants
Authorization: Bearer {super-admin-token}Required Permission: read:tenants
Create Tenant (Super Admin)
POST /api/tenants
Authorization: Bearer {super-admin-token}Required Permission: create:tenants
Request Body:
{
"name": "New Company",
"identifier": "newcompany",
"domain": "newcompany.yourapp.com",
"settings": {
"timezone": "America/New_York",
"language": "en-US"
}
}Get Current Tenant
GET /api/tenants/current
Authorization: Bearer {token}Tenant Switching
Tenant switching is done via POST /api/auth/switch-tenant - see Auth Endpoints.
Error Response Format
All error responses follow this format:
{
"isSuccess": false,
"errorCode": "ERROR_CODE",
"errorMessage": "Human-readable error message",
"errors": [
{
"field": "email",
"message": "Invalid email format"
}
]
}Common Error Codes
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR | 400 | Request validation failed |
INVALID_CREDENTIALS | 401 | Invalid email or password |
TOKEN_EXPIRED | 401 | Access token has expired |
TOKEN_INVALID | 401 | Token is invalid |
UNAUTHORIZED | 401 | Authentication required |
FORBIDDEN | 403 | Permission denied |
NOT_FOUND | 404 | Resource not found |
CONFLICT | 409 | Resource already exists |
ACCOUNT_LOCKED | 423 | Account is locked |
RATE_LIMITED | 429 | Too many requests |
INTERNAL_ERROR | 500 | Internal server error |
Rate Limits
| Endpoint | Limit |
|---|---|
/api/auth/login | 10 requests/minute |
/api/auth/register | 5 requests/minute |
/api/auth/request-password-reset | 3 requests/minute |
| Other endpoints | 100 requests/minute |
Pagination
Paginated endpoints support these query parameters:
| Parameter | Type | Default | Max |
|---|---|---|---|
page | int | 1 | - |
pageSize | int | 20 | 100 |
sortBy | string | varies | - |
sortDirection | string | asc | - |