The centralized identity and authentication platform for the Orzatty ecosystem. OAuth2/OpenID Connect SSO, multi-organization management, and a TypeScript SDK powering authentication across 27+ services.
As the Orzatty ecosystem grows beyond a single application into a suite of interconnected services — Sylor (AI assistant), OrzattyCloud CDN, OrzattyOS, Rany IDE, OpenRany, and others — the authentication problem becomes a first-class infrastructure challenge. Each service managing its own user accounts creates:
OrzattyAccount resolves this by providing a single identity layer: one account, one login, all services. Architecturally, it is modeled after enterprise identity platforms like Auth0, Google Identity Platform, and Okta — but built in-house to maintain data sovereignty and eliminate vendor dependency.
OrzattyAccount is a Cargo-workspace-style TypeScript monorepo with 7 independent services communicating over internal REST APIs. Each service owns its data domain and can be scaled, deployed, and updated independently:
Single entry point. Routes all external requests. Handles rate limiting, request validation, and service discovery.
Core login/register logic. Password verification (bcrypt). Token issuance. Session lifecycle management.
Full OAuth2 + OpenID Connect provider. Authorization code flow, PKCE, implicit flow, client credentials.
Distributed session management backed by Redis. Session revocation, active session listing, device tracking.
User profile CRUD. Privacy settings. MFA enrollment. Audit log access.
Multi-org management. RBAC roles. Invitation system. Domain restrictions. Custom security policies per org.
Material Design 3 account management UI. Equivalent to Google Account — full profile, security, and privacy controls.
All inter-service traffic is internal to the cluster (not exposed externally) and authenticated with service-to-service API keys. Services communicate synchronously for critical auth paths and asynchronously via an internal event bus for audit logging and cache invalidation:
External Request
→ API Gateway (Port 8000) — validates JWT, rate limits, routes
→ Auth Service (Port 8001) — credential verification
→ Session Service (Port 8003) — token refresh, session management
→ User Service (Port 8004) — profile reads/writes
→ Organization Service (Port 8005) — RBAC enforcement
→ OAuth Service (Port 8002) — third-party app authorization
OrzattyAccount implements the OAuth2 Authorization Code flow with PKCE (Proof Key for Code Exchange) as the primary authentication mechanism for all Orzatty services. This prevents authorization code interception attacks on mobile and single-page applications:
// 1. Client app generates a code verifier and code challenge
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto.createHash('sha256')
.update(codeVerifier).digest('base64url');
// 2. Redirect user to OrzattyAccount authorization endpoint
const authUrl = new URL('https://account.orzatty.com/oauth2/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
// 3. User authenticates, OrzattyAccount returns code
// 4. Client exchanges code for tokens
const tokenResponse = await fetch('https://account.orzatty.com/oauth2/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: REDIRECT_URI,
code_verifier: codeVerifier, // Proves ownership of code challenge
client_id: CLIENT_ID,
}),
});
const { access_token, id_token, refresh_token } = await tokenResponse.json();
All configuration metadata is published at the standard discovery endpoint, enabling any compliant OIDC library to automatically configure itself:
GET /.well-known/openid-configuration
{
"issuer": "https://account.orzatty.com",
"authorization_endpoint": "https://account.orzatty.com/oauth2/authorize",
"token_endpoint": "https://account.orzatty.com/oauth2/token",
"userinfo_endpoint": "https://account.orzatty.com/oauth2/userinfo",
"jwks_uri": "https://account.orzatty.com/oauth2/jwks",
"scopes_supported": ["openid", "profile", "email", "phone", "org:read", "org:write"],
"response_types_supported": ["code", "token", "id_token"],
"code_challenge_methods_supported": ["S256"]
}
Passwords are hashed using bcrypt with a configurable work factor (default: 12 rounds, equivalent to ~300ms verification time). The work factor is designed to resist brute-force attacks while maintaining a reasonable user experience. Argon2id migration is planned for OrzattyAccount v2.
Sessions are stored in Redis with a sliding expiration window. Each session includes:
{
"session_id": "sess_01HXK7...", // 128-bit random session identifier
"user_id": "usr_01HXK7...",
"device_fingerprint": "sha256:...", // Browser/device signature
"ip_address": "190.x.x.x", // Logged for impossible-travel detection
"created_at": "2026-03-21T21:00:00Z",
"last_active": "2026-03-21T21:05:00Z",
"expires_at": "2026-04-21T21:00:00Z" // 30-day sliding window
}
All authentication endpoints are protected by a GCRA (Generic Cell Rate Algorithm) rate limiter at the API Gateway level, preventing credential stuffing attacks:
POST /api/auth/login — 5 attempts per IP per 15 minutesPOST /api/auth/register — 3 attempts per IP per hourPOST /api/auth/forgot-password — 3 attempts per IP per hour/api/auth/login — Credential validation, returns access + refresh tokens/api/auth/register — New account creation with email verification/api/auth/logout — Revoke current session token/api/auth/refresh — Exchange refresh token for new access token/api/auth/forgot-password — Initiate password reset via email/api/auth/mfa/enable — Enroll TOTP MFA device/api/auth/mfa/verify — Verify TOTP code/oauth2/authorize — Authorization endpoint (redirects with code)/oauth2/token — Token exchange endpoint/oauth2/userinfo — Returns user profile for valid access token/oauth2/jwks — JSON Web Key Set for token signature verification/.well-known/openid-configuration — OIDC discovery document/api/users/profile — Get authenticated user's profile/api/users/profile — Update profile fields/api/users/sessions — List all active sessions for user/api/users/sessions/:id — Revoke a specific session/api/users/audit-log — Paginated account activity logServices integrating with OrzattyAccount use the official TypeScript SDK, which handles token validation, user info retrieval, and webhook registration without requiring services to implement the OAuth2 flow from scratch:
import { OrzattyAuthSDK } from '@orzattyholding/account-sdk';
const auth = new OrzattyAuthSDK({
apiUrl: 'https://account.orzatty.com',
apiKey: process.env.ORZATTY_SERVICE_KEY, // Per-service API key issued by OrzattyAccount
timeout: 5000, // ms — fail-fast for auth critical paths
});
// Validate an incoming request token (used in middleware)
app.use(async (req, res, next) => {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'Unauthorized' });
try {
const user = await auth.validateToken(token);
req.user = user; // { id, email, name, orgs: [...] }
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid or expired token' });
}
});
// Check organization membership before granting access
async function requireOrgRole(userId: string, orgId: string, minRole: string) {
const membership = await auth.getOrgMembership(userId, orgId);
if (!membership || !hasRole(membership.role, minRole)) {
throw new UnauthorizedError('Insufficient organization role');
}
}
// Register a webhook for user login events
await auth.registerWebhook({
eventType: 'user.login',
url: 'https://sylor.orzatty.com/webhooks/user-login',
secret: process.env.WEBHOOK_SECRET, // Used to sign HMAC-SHA256 payloads
active: true,
});
// Verify incoming webhook payload signature
app.post('/webhooks/user-login', (req, res) => {
const isValid = auth.verifyWebhookSignature(
req.body,
req.headers['x-orzatty-signature'],
process.env.WEBHOOK_SECRET
);
if (!isValid) return res.status(401).send('Invalid signature');
// Handle event...
});
OrzattyAccount supports multi-tenancy at the organizational level. Users can belong to multiple organizations simultaneously and switch contexts seamlessly. This enables enterprise deployments where a company may use Orzatty services under their own branded organization with custom policies.
Five roles are defined with a hierarchical permission model:
| Permission | Owner | Admin | Member | Billing | Viewer |
|---|---|---|---|---|---|
| Manage organization settings | ✓ | ✓ | — | — | — |
| Invite / remove members | ✓ | ✓ | — | — | — |
| Access all services | ✓ | ✓ | ✓ | — | Read |
| Manage billing & subscriptions | ✓ | — | — | ✓ | — |
| View audit logs | ✓ | ✓ | — | — | — |
| Delete organization | ✓ | — | — | — | — |
Organizations can restrict membership to users with verified email addresses from approved domains. For example, an enterprise deploying Orzatty services can restrict their organization to @company.com email addresses, ensuring that only verified corporate users can join.
OrzattyAccount emits signed webhooks for all significant identity events, enabling downstream services to react in real-time to user actions without polling the API:
| Event Type | Trigger | Typical Consumer |
|---|---|---|
user.login | Successful authentication | CENTINELA (threat correlation), Sylor (session setup) |
user.register | New account created | Onboarding flows, welcome emails |
user.logout | Session terminated | Revoke service-level caches |
user.mfa_enabled | MFA enrolled | Security notifications |
org.member_added | User joins organization | Access provisioning |
org.member_removed | User leaves organization | Access revocation, offboarding |
session.suspicious | Impossible travel or anomaly detected | CENTINELA, MFA re-challenge |
All webhook payloads are signed with HMAC-SHA256 using the registered webhook secret. The signature is delivered in the X-Orzatty-Signature header as sha256=<hex_digest>, following the same convention as GitHub webhooks.
All persistent identity data (users, organizations, OAuth clients, refresh tokens) is stored in PostgreSQL. The schema uses UUIDs as primary keys (not sequential integers) to prevent enumeration attacks. Row-level security policies at the database level enforce data isolation between organizations.
Active sessions, TOTP challenges, and rate limiter state are stored in Redis with TTL-based expiration. Redis's atomic operations (INCR, GETSET) are used for rate limiting counters, preventing race conditions that could allow burst attacks to slip through.
Because all state is externalized (PostgreSQL + Redis), every OrzattyAccount service is stateless and can be horizontally scaled behind a load balancer without session affinity requirements. The Docker Compose configuration supports multi-instance deployment with shared database and cache:
docker-compose -f docker-compose.prod.yml up --scale api-gateway=3 \
--scale auth-service=2 --scale session-service=3
/health on every service (database connectivity + Redis ping) — used by Kubernetes liveness/readiness probes/metrics — request counts, authentication success/failure rates, token validation latencytrace_id, service_name, user_id (when available), and duration_ms| Version | Target | Feature |
|---|---|---|
| 1.0 | Q2 2026 | Production release. Full OAuth2/OIDC, MFA, multi-org, @orzattyholding/account-sdk v1.0 |
| 1.1 | Q2 2026 | Passkey (WebAuthn/FIDO2) support — passwordless authentication |
| 1.2 | Q3 2026 | Social login providers: Google, GitHub (OAuth2 delegation) |
| 2.0 | Q4 2026 | Argon2id password hashing migration. Enterprise SAML 2.0 SSO integration |
| 2.1 | Q1 2027 | OrzattyOS PAM module production release. Desktop SSO across all ecosystem apps |