@ortha/server-identity
v0.0.4
Published
JWT-based authentication, role/permission system, and invite code management for the Ortha server. Provides Fastify hooks for route-level auth and permission enforcement, plus the Sequelize schema for identity models.
Readme
@ortha/server-identity
JWT-based authentication, role/permission system, and invite code management for the Ortha server. Provides Fastify hooks for route-level auth and permission enforcement, plus the Sequelize schema for identity models.
Installation
Internal monorepo dependency — import directly:
import {
identityServerPlugin,
identitySchema,
authHook,
permissionHook
} from '@ortha/server-identity';Usage
Registering the plugin
import { bootstrap } from '@ortha/server-platform-bootstrap';
import { databasePlugin } from '@ortha/server-platform-database';
import { identityServerPlugin, identitySchema } from '@ortha/server-identity';
await bootstrap({
config: bootstrapConfig,
plugins: [
databasePlugin({
...dbConfig,
schemas: [identitySchema]
}),
identityServerPlugin({
jwtSecret: 'your-secret',
accessExpiry: '15m',
refreshExpiry: '7d',
signupExpiry: '1h'
})
]
});Using auth hooks in other plugins
import { authHook, permissionHook } from '@ortha/server-identity';
fastify.route({
method: 'GET',
url: '/api/my-resource',
config: {
auth: true,
permissions: ['read:admin:resource']
},
onRequest: [authHook, permissionHook],
handler: async (request, reply) => {
const user = request.user; // populated by authHook
}
});Hashing passwords
import { hashPassword } from '@ortha/server-identity';
const hashed = await hashPassword('plaintext-password');Routes
| Method | Path | Auth | Permissions | Description |
| ------ | ----------------------------- | ---- | ------------------- | -------------------- |
| POST | /api/identity/login | No | — | Authenticate user |
| POST | /api/identity/signup | No | — | Register new user |
| POST | /api/identity/invite/verify | No | — | Verify invite code |
| POST | /api/identity/refresh | No | — | Refresh access token |
| GET | /api/identity/me | Yes | — | Get current user |
| POST | /api/identity/invite/create | Yes | create:admin:user | Create invite code |
| GET | /api/identity/roles | Yes | read:admin:user | List available roles |
Error Contract
Identity routes return Fastify error fields plus structured metadata:
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid credentials",
"code": "AUTH_INVALID_CREDENTIALS",
"path": "root",
"details": [
{
"code": "AUTH_INVALID_CREDENTIALS",
"path": "root",
"message": "Invalid credentials"
}
]
}Validation errors return details[] with one entry per issue. Paths use dot notation (e.g. email, password, code).
API Reference
Plugin & Schema
| Export | Kind | Description |
| ------------------------ | ------- | ------------------------------------------------ |
| identityServerPlugin() | factory | Fastify plugin — registers identity routes |
| identitySchema | schema | Sequelize SchemaDefinition for identity models |
Hooks
| Export | Kind | Description |
| ---------------- | ---- | --------------------------------------------- |
| authHook | hook | Fastify onRequest — validates Bearer token |
| permissionHook | hook | Fastify onRequest — checks user permissions |
Utilities
| Export | Kind | Description |
| ------------------ | -------- | --------------------------------------- |
| hashPassword() | function | Bcrypt hash with 12 salt rounds |
| getRequestUser() | function | Extract typed user from Fastify request |
Types
| Export | Kind | Description |
| ---------------------- | ---- | ----------------------------------- |
| IdentityPluginConfig | type | Plugin configuration (JWT settings) |
| JwtConfig | type | JWT secret and expiry configuration |
| AccessTokenPayload | type | JWT access token payload shape |
Configuration
| Property | Type | Description |
| --------------- | -------- | ---------------------------------- |
| jwtSecret | string | Secret key for JWT signing |
| accessExpiry | string | Access token expiry (e.g. '15m') |
| refreshExpiry | string | Refresh token expiry (e.g. '7d') |
| signupExpiry | string | Signup token expiry (e.g. '1h') |
Sequelize Models
| Model | Description |
| ------------ | ---------------------------------------- |
| User | Core user record (email, name, isActive) |
| Password | Hashed password (belongs to User) |
| Role | Named role (e.g. admin, editor) |
| Permission | Action-resource pair (belongs to Role) |
| InviteCode | Time-limited invite code for signup |
Internal Structure
src/lib/
├── types/index.ts # Shared types and interfaces
├── schemas/index.ts # Sequelize model definitions + associations
├── identityServerPlugin/index.ts # Fastify plugin factory
├── controllers/ # Route handlers
├── services/
│ ├── utils/ # Shared service utilities
│ ├── login/index.ts # Login flow
│ ├── signup/index.ts # Signup flow
│ ├── refresh/index.ts # Token refresh
│ ├── hashPassword/index.ts # Bcrypt hashing
│ ├── verifyPassword/index.ts # Bcrypt verification
│ ├── signAccessToken/index.ts # JWT access token signing
│ ├── signRefreshToken/index.ts # JWT refresh token signing
│ ├── signSignupToken/index.ts # JWT signup token signing
│ ├── verifyToken/index.ts # JWT verification
│ ├── verifyInviteCode/index.ts # Invite code validation
│ ├── createInvite/index.ts # Invite code creation
│ ├── serializeMe/index.ts # Current user serialization
│ └── listRoles/index.ts # Role listing
├── hooks/
│ ├── authHook/index.ts # Bearer token validation
│ └── permissionHook/index.ts # Permission enforcement
└── dto/ # Data transfer objectsKey Patterns
- Declarative auth via route
config.authandconfig.permissionsproperties. - Auth hook validates Bearer token and populates
request.user. - Permission hook checks user's role permissions against required route permissions.
- Services use dependency injection:
serviceName(deps)(args). - Bcrypt uses 12 salt rounds for password hashing.
Dependencies
@ortha/server-platform-database—SchemaDefinition,ModelRegistrytypes@ortha/server-utils— error response builders@fastify/jwt— JWT signing and verification
Building
nx build server-identity