@vunexa/lixa 0.1.6-alpha.15 → 0.1.6-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,311 +1,292 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/vunexa/lixa/master/docs/assets/lixa-banner.png" alt="Lixa Banner" width="600" onerror="this.style.display='none'"/>
3
- </p>
1
+ # @vunexa/lixa
4
2
 
5
- # 🚀 Lixa (`@vunexa/lixa`)
3
+ **A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library for Node.js.**
6
4
 
7
- > **The modern, developer-first TypeScript authentication & authorization framework for Node.js.**
8
- > Built for zero-friction developer experience, strict AuthN/AuthZ separation, multi-SSO account linking, normalized database persistence, and blazing-fast in-memory caching.
5
+ Lixa simplifies multi-provider authentication, identity management, and third-party resource authorization into a single, type-safe API. Use it with any OAuth provider — Google, GitHub, Microsoft, AWS Cognito, or your own custom provider — without being locked in to any vendor.
9
6
 
10
- [![npm version](https://img.shields.io/npm/v/@vunexa/lixa.svg?color=blue)](https://www.npmjs.com/package/@vunexa/lixa)
11
- [![npm downloads](https://img.shields.io/npm/dm/@vunexa/lixa.svg)](https://www.npmjs.com/package/@vunexa/lixa)
7
+ [![npm version](https://img.shields.io/npm/v/@vunexa/lixa.svg)](https://www.npmjs.com/package/@vunexa/lixa)
12
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
13
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
+
10
+ 📖 **Full Documentation:** [lixa.vunexa.app](https://lixa.vunexa.app)
14
11
 
15
12
  ---
16
13
 
17
- ## 📑 Table of Contents
18
-
19
- - [Why Lixa?](#-why-lixa)
20
- - [Key Features](#-key-features)
21
- - [Architecture & Sequence Diagrams](#-architecture--sequence-diagrams)
22
- - [1. Authentication Flow (AuthN)](#1-authentication-flow-authn)
23
- - [2. Post-Login Resource Connection (AuthZ)](#2-post-login-resource-connection-authz)
24
- - [3. Multi-SSO Account Linking](#3-multi-sso-account-linking)
25
- - [Installation](#-installation)
26
- - [Quickstart: AWS Cognito + Express + Prisma](#-quickstart-aws-cognito--express--prisma)
27
- - [Step 1: Database Schema (Prisma)](#step-1-database-schema-prisma)
28
- - [Step 2: Initialize Lixa & Storage with 2-Minute Cache](#step-2-initialize-lixa--storage-with-2-minute-cache)
29
- - [Step 3: Setup Express Server & Routes](#step-3-setup-express-server--routes)
30
- - [Step 4: Protect Routes & Use Tokens](#step-4-protect-routes--use-tokens)
31
- - [Connecting External Resources (AuthZ)](#-connecting-external-resources-authz)
32
- - [In-Memory 2-Minute Caching (`withLocalCache`)](#-in-memory-2-minute-caching-withlocalcache)
33
- - [Supported Identity Providers](#-supported-identity-providers)
34
- - [TypeScript API Reference](#-typescript-api-reference)
35
- - [Contributing & License](#-contributing--license)
14
+ ## Table of Contents
15
+
16
+ - [Why Lixa?](#why-lixa)
17
+ - [Architecture Overview](#architecture-overview)
18
+ - [Installation](#installation)
19
+ - [Quick Start](#quick-start)
20
+ - [Identity Providers](#identity-providers)
21
+ - [AWS Cognito](#aws-cognito)
22
+ - [Auth0](#auth0)
23
+ - [Okta](#okta)
24
+ - [Self-Managed (Database)](#self-managed-database)
25
+ - [Composite (Multiple Backends)](#composite-multiple-backends)
26
+ - [OAuth / SSO Providers](#oauth--sso-providers)
27
+ - [Built-in Providers](#built-in-providers)
28
+ - [Custom Providers](#custom-providers)
29
+ - [Credentials Authentication](#credentials-authentication)
30
+ - [Session Management](#session-management)
31
+ - [Account Linking](#account-linking)
32
+ - [Resource Connections (AuthZ)](#resource-connections-authz)
33
+ - [Database Storage](#database-storage)
34
+ - [Express Integration](#express-integration)
35
+ - [Error Handling](#error-handling)
36
+ - [API Reference](#api-reference)
37
+ - [License](#license)
36
38
 
37
39
  ---
38
40
 
39
- ## 💡 Why Lixa?
40
-
41
- Most auth libraries blur the line between **authenticating a user** (AuthN) and **requesting access to third-party APIs** (AuthZ). They cram bloated, multi-token JSON blobs into session cookies or single database rows, making user sessions fragile, bloated, and vulnerable.
41
+ ## Why Lixa?
42
42
 
43
- **Lixa solves this cleanly:**
44
- 1. **Single-Purpose Sessions**: A user session contains *only* the authentication tokens (`accessToken`, `refreshToken`, `idToken`) needed for that specific session.
45
- 2. **First-Class Normalized Database Columns**: No opaque JSON blobs. Every table (`sessions`, `user_accounts`, `user_resources`, `oauth_states`, `user_credentials`) uses primitive typed columns (`userId`, `provider`, `accessToken`, `expiresAt`, etc.) with built-in database indexing.
46
- 3. **Built-in 2-Minute Local In-Memory Cache**: Eliminates redundant database reads on high-frequency API endpoints while guaranteeing safe invalidation on logout or token updates.
47
- 4. **Universal Multi-SSO Account Linking**: Seamlessly links AWS Cognito, Google, GitHub, Okta, Auth0, or username/password credentials to a single unified user ID by verified email.
48
- 5. **Zero-Boilerplate DevXP**: Type-safe out of the box, with full Express middleware, Prisma and Drizzle ORM adapters, and automatic PKCE security.
43
+ | Feature | Lixa |
44
+ |---------|------|
45
+ | **Provider-agnostic** | Works with any OAuth 2.0 / OIDC provider |
46
+ | **Identity Management** | Built-in support for AWS Cognito, Auth0, Okta, or self-managed DB credentials |
47
+ | **PKCE by default** | Every OAuth flow uses RFC 7636 PKCE (S256) automatically |
48
+ | **AuthN / AuthZ separation** | Clean separation between login (identity) and post-login API access (resource connections) |
49
+ | **Account linking** | Auto-link multiple SSO providers (Google + GitHub + Cognito) under a single user |
50
+ | **Type-safe** | Full TypeScript with inferred provider keys and generic session types |
51
+ | **Zero vendor lock-in** | No AWS SDK, no Auth0 SDK — just `fetch()` calls to standard APIs |
52
+ | **Minimal dependencies** | Only `node-cache` as runtime dependency |
49
53
 
50
54
  ---
51
55
 
52
- ## ✨ Key Features
56
+ ## Architecture Overview
57
+
58
+ Lixa is organized into a lightweight, modular **2-package architecture**:
53
59
 
54
- - 🛡️ **Strict AuthN / AuthZ Separation**: Identity tokens stay in `sessions`. External API tokens (e.g. GitHub repos, Google Drive) are isolated in `user_resources`.
55
- - ⚡ **2-Minute In-Memory Cache (`withLocalCache`)**: Blazing-fast response times for session checks and user lookups with zero SQLite/Postgres I/O overhead.
56
- - 🔗 **Multi-SSO Account Linking**: Automatic or interactive linking of multiple identity providers under one user account.
57
- - 🗄️ **Clean Database Schema**: Fully normalized Prisma and Drizzle models with primitive column types and indexed foreign keys.
58
- - 🔐 **PKCE & State Validation**: Automatic RFC 7636 Proof Key for Code Exchange and cryptographic CSRF state verification.
59
- - ☁️ **Enterprise Identity Backends**: First-class support for **AWS Cognito**, **Auth0**, **Okta**, and **Self-Managed Database** credentials.
60
+ ```
61
+ ┌──────────────────────────────────────────────────────────────┐
62
+ │ Your Application │
63
+ ├──────────────────────────────────────────────────────────────┤
64
+ │ │
65
+ │ ┌────────────────────────────────────────────────────────┐ │
66
+ │ │ @vunexa/lixa (Core Engine) │ │
67
+ │ │ │ │
68
+ │ │ • Lixa class • OAuth 2.0 + PKCE flows │ │
69
+ │ │ • IProvider • Session / State management │ │
70
+ │ │ • IIdentityProvider • Credentials (scrypt hashing) │ │
71
+ │ │ • Account linking • Resource connections (AuthZ) │ │
72
+ │ │ • Cookie utilities • Structured error hierarchy │ │
73
+ │ └────────────────────────────────────────────────────────┘ │
74
+ │ ▲ │
75
+ │ │ peer dependency │
76
+ │ ┌────────────────────────┴───────────────────────────────┐ │
77
+ │ │ @vunexa/lixa-extensions (Extensions) │ │
78
+ │ │ │ │
79
+ │ │ • OAuth Providers: Google, GitHub, Microsoft, Cognito │ │
80
+ │ │ • Identity: CognitoIdentityProvider, Auth0, Okta │ │
81
+ │ │ • Storage: Prisma adapter, Drizzle adapter, Cache │ │
82
+ │ │ • HTTP: Express route handlers & middleware │ │
83
+ │ └────────────────────────────────────────────────────────┘ │
84
+ │ │
85
+ └──────────────────────────────────────────────────────────────┘
86
+ ```
60
87
 
61
88
  ---
62
89
 
63
- ## 📐 Architecture & Sequence Diagrams
64
-
65
- ### 1. Authentication Flow (AuthN)
66
-
67
- This sequence diagram illustrates how a user logs in via AWS Cognito (or Google/GitHub SSO), receives a secure session cookie, and benefits from Lixa's 2-minute memory cache:
68
-
69
- ```mermaid
70
- sequenceDiagram
71
- autonumber
72
- actor User as User Browser
73
- participant Express as Express App (Lixa Middleware)
74
- participant Lixa as Lixa Engine
75
- participant Cache as In-Memory Cache (120s TTL)
76
- participant DB as Prisma / Database
77
- participant Cognito as AWS Cognito (OIDC / Hosted UI)
78
-
79
- User->>Express: GET /api/v1/auth/login?provider=cognito
80
- Express->>Lixa: getAuthUrl("cognito")
81
- Lixa->>DB: Store state & PKCE codeVerifier in `oauth_states`
82
- Lixa-->>Express: Return Authorization URL
83
- Express-->>User: 302 Redirect to AWS Cognito
84
-
85
- User->>Cognito: User signs in & consents
86
- Cognito-->>User: 302 Redirect to /api/v1/auth/callback?code=...&state=...
87
-
88
- User->>Express: GET /api/v1/auth/callback?code=...&state=...
89
- Express->>Lixa: handleCallback("cognito", code, state)
90
- Lixa->>DB: Validate & delete state from `oauth_states`
91
- Lixa->>Cognito: Exchange code + PKCE verifier for tokens (AT, RT, idToken)
92
- Cognito-->>Lixa: Return Cognito Tokens & User Claims
93
- Lixa->>DB: Upsert normalized row in `sessions` (userId, AT, RT, idToken)
94
- Lixa->>Cache: Cache session for 120 seconds
95
- Lixa-->>Express: Issue Session ID (UUID)
96
- Express-->>User: Set-Cookie: app_session=<sessionId>; HttpOnly; Secure
97
-
98
- Note over User, Express: Subsequent Authenticated Requests
99
- User->>Express: GET /api/v1/me (Cookie: app_session=...)
100
- Express->>Cache: Check session in memory cache
101
- alt Cache Hit (< 2 mins)
102
- Cache-->>Express: Return cached session (0 DB queries!)
103
- else Cache Miss / Expired
104
- Express->>DB: Query `sessions` by id
105
- DB-->>Express: Return session & refresh cache
106
- end
107
- Express-->>User: 200 OK (User Profile)
90
+ ## Installation
91
+
92
+ ```bash
93
+ npm install @vunexa/lixa @vunexa/lixa-extensions
108
94
  ```
109
95
 
110
- ---
96
+ ```bash
97
+ # yarn
98
+ yarn add @vunexa/lixa @vunexa/lixa-extensions
111
99
 
112
- ### 2. Post-Login Resource Connection (AuthZ)
113
-
114
- When an authenticated user grants your application access to external APIs (e.g. GitHub repos or Google Drive), tokens are stored in `user_resources` and bound to the user's account—completely separate from their login session:
115
-
116
- ```mermaid
117
- sequenceDiagram
118
- autonumber
119
- actor User as Authenticated User
120
- participant Express as Express App
121
- participant Lixa as Lixa Engine
122
- participant DB as Database (`user_resources`)
123
- participant GitHub as GitHub OAuth (Resource Provider)
124
-
125
- User->>Express: GET /api/v1/resources/connect/github
126
- Express->>Lixa: getResourceAuthUrl("github", { userId: req.session.userId })
127
- Lixa-->>Express: Return OAuth URL with resource scopes (`repo`, `read:user`)
128
- Express-->>User: 302 Redirect to GitHub OAuth
129
-
130
- User->>GitHub: Authorize application for repository access
131
- GitHub-->>User: 302 Redirect to /api/v1/resources/callback/github?code=...
132
-
133
- User->>Express: GET /api/v1/resources/callback/github?code=...
134
- Express->>Lixa: handleResourceCallback("github", code, userId)
135
- Lixa->>GitHub: Exchange authorization code for Resource Access Token
136
- GitHub-->>Lixa: Return Access Token & Scopes
137
- Lixa->>DB: Save to `user_resources` (userId, provider="github", accessToken, scopes)
138
- Lixa-->>Express: Resource Connected
139
- Express-->>User: 200 OK: GitHub Connected Successfully!
140
-
141
- Note over Express, GitHub: Background Tasks / API Requests
142
- Express->>DB: Get GitHub Resource Token for userId
143
- Express->>GitHub: Fetch user repositories with Resource Token
144
- GitHub-->>Express: Repository List
100
+ # pnpm
101
+ pnpm add @vunexa/lixa @vunexa/lixa-extensions
145
102
  ```
146
103
 
147
104
  ---
148
105
 
149
- ### 3. Multi-SSO Account Linking
106
+ ## Quick Start
150
107
 
151
- Lixa automatically links multiple identity providers (e.g. AWS Cognito + Google) sharing the same verified email address:
108
+ Get up and running with Google OAuth in under 5 minutes:
152
109
 
153
- ```mermaid
154
- sequenceDiagram
155
- autonumber
156
- actor User as User with alex@example.com
157
- participant Lixa as Lixa Engine
158
- participant DB as Database (`user_accounts`)
159
-
160
- Note over User, DB: User previously registered with AWS Cognito (userId="usr_123")
161
- User->>Lixa: Signs in via Google SSO (email="alex@example.com", verified=true)
162
- Lixa->>DB: Find existing account by verified email in `user_accounts`
163
- DB-->>Lixa: Found existing account (userId="usr_123", provider="cognito")
164
- Lixa->>DB: Link Google identity to same userId in `user_accounts` (userId="usr_123", provider="google")
165
- Lixa->>DB: Create active session for userId="usr_123"
166
- Lixa-->>User: Logged in! Unified profile and data preserved across both logins.
167
- ```
110
+ ```typescript
111
+ import { Lixa } from "@vunexa/lixa";
112
+ import { GoogleProvider, GithubProvider } from "@vunexa/lixa-extensions/providers";
168
113
 
169
- ---
114
+ // 1. Create a Lixa instance with your providers
115
+ const lixa = new Lixa({
116
+ providers: {
117
+ google: {
118
+ provider: new GoogleProvider(),
119
+ clientId: process.env.GOOGLE_CLIENT_ID!,
120
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
121
+ redirectUri: "http://localhost:3000/auth/google/callback",
122
+ scopes: ["openid", "email", "profile"],
123
+ },
124
+ github: {
125
+ provider: new GithubProvider(),
126
+ clientId: process.env.GITHUB_CLIENT_ID!,
127
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
128
+ redirectUri: "http://localhost:3000/auth/github/callback",
129
+ scopes: ["read:user", "user:email"],
130
+ },
131
+ },
132
+ });
170
133
 
171
- ## 📦 Installation
134
+ // 2. Generate an authorization URL and redirect the user
135
+ const authUrl = await lixa.getAuthUrl("google");
136
+ // → Redirect user to authUrl
172
137
 
173
- ```bash
174
- # Core framework & official extensions
175
- npm install @vunexa/lixa @vunexa/lixa-extensions
138
+ // 3. Handle the callback after the user authorizes
139
+ const sessionId = await lixa.handleCallback({
140
+ provider: "google",
141
+ code: "authorization_code_from_query",
142
+ state: "state_from_query",
143
+ });
176
144
 
177
- # If using Prisma ORM (recommended)
178
- npm install @prisma/client
179
- npm install -D prisma
145
+ // 4. Fetch session info anywhere in your app
146
+ const session = await lixa.fetchSessionInfo(sessionId);
147
+ // → { sessionId, userId, email, provider: "google", token, raw }
180
148
  ```
181
149
 
182
150
  ---
183
151
 
184
- ## 🏁 Quickstart: AWS Cognito + Express + Prisma
152
+ ## Identity Providers
185
153
 
186
- Here is a complete, production-ready example configuring **AWS Cognito SSO**, **Prisma storage with 2-minute caching**, and **Express**.
154
+ Lixa supports multiple identity backends for username/password authentication alongside OAuth SSO. Configure them via the `identityProvider` (or `identity`) field in `LixaConfig`.
187
155
 
188
- ### Step 1: Database Schema (Prisma)
156
+ ### AWS Cognito
189
157
 
190
- Create or update your `prisma/schema.prisma` file with normalized primitive columns:
158
+ The most mature integration. Communicates directly with AWS Cognito REST APIs — **zero AWS SDK dependency**.
191
159
 
192
- ```prisma
193
- datasource db {
194
- provider = "sqlite" // or "postgresql", "mysql"
195
- url = env("DATABASE_URL")
196
- }
160
+ ```typescript
161
+ import { Lixa, CompositeIdentityProvider } from "@vunexa/lixa";
162
+ import { CognitoIdentityProvider } from "@vunexa/lixa-extensions/identity/cognito";
163
+ import { GoogleProvider } from "@vunexa/lixa-extensions/providers";
164
+
165
+ // Option A: Cognito-only (username/password via User Pool)
166
+ const lixa = new Lixa({
167
+ identity: new CognitoIdentityProvider({
168
+ userPoolId: process.env.COGNITO_USER_POOL_ID!,
169
+ clientId: process.env.COGNITO_CLIENT_ID!,
170
+ region: "us-east-1",
171
+ clientSecret: process.env.COGNITO_CLIENT_SECRET, // optional
172
+ }),
173
+ });
197
174
 
198
- generator client {
199
- provider = "prisma-client-js"
200
- }
175
+ // Option B: Cognito + Hosted UI federated SSO (Google, Apple, SAML, etc.)
176
+ const cognito = new CognitoIdentityProvider({
177
+ userPoolId: process.env.COGNITO_USER_POOL_ID!,
178
+ clientId: process.env.COGNITO_CLIENT_ID!,
179
+ region: "us-east-1",
180
+ clientSecret: process.env.COGNITO_CLIENT_SECRET,
181
+ hostedUi: {
182
+ domain: "https://my-pool.auth.us-east-1.amazoncognito.com",
183
+ redirectUri: "http://localhost:3000/auth/cognito/callback",
184
+ federated: {
185
+ google: { identityProvider: "Google" },
186
+ apple: { identityProvider: "SignInWithApple" },
187
+ },
188
+ },
189
+ });
201
190
 
202
- // 1. Active User Sessions (AuthN)
203
- model Session {
204
- id String @id @map("id")
205
- userId String? @map("user_id")
206
- userEmail String? @map("user_email")
207
- provider String? @map("provider")
208
- accessToken String? @map("access_token")
209
- refreshToken String? @map("refresh_token")
210
- idToken String? @map("id_token")
211
- expiresAt DateTime @map("expires_at")
212
- createdAt DateTime @default(now()) @map("created_at")
213
- updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
214
-
215
- @@index([userId])
216
- @@index([userEmail])
217
- @@index([expiresAt])
218
- @@map("sessions")
219
- }
191
+ const lixaWithSSO = new Lixa({
192
+ identity: cognito,
193
+ // cognito.getProviders() auto-registers 'cognito_sso', 'cognito_google', 'cognito_apple'
194
+ });
195
+ ```
220
196
 
221
- // 2. Multi-SSO Linked Identity Accounts (AuthN)
222
- model UserAccount {
223
- userId String @map("user_id")
224
- provider String @map("provider")
225
- providerUserId String? @map("provider_user_id")
226
- email String? @map("email")
227
- linkedAt DateTime @default(now()) @map("linked_at")
228
- updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
229
-
230
- @@id([userId, provider])
231
- @@index([email])
232
- @@map("user_accounts")
233
- }
197
+ **Cognito API coverage:**
234
198
 
235
- // 3. Connected Third-Party API Resources (AuthZ)
236
- model ConnectedResource {
237
- userId String @map("user_id")
238
- provider String @map("provider")
239
- accessToken String @map("access_token")
240
- refreshToken String? @map("refresh_token")
241
- idToken String? @map("id_token")
242
- scopes String? @map("scopes")
243
- expiresAt DateTime? @map("expires_at")
244
- connectedAt DateTime @default(now()) @map("connected_at")
245
- updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
246
-
247
- @@id([userId, provider])
248
- @@map("user_resources")
249
- }
199
+ | Method | Cognito API Action |
200
+ |--------|--------------------|
201
+ | `lixa.signUp()` | `SignUp` |
202
+ | `lixa.signIn()` | `InitiateAuth` (USER_PASSWORD_AUTH) |
203
+ | `lixa.confirmSignUp()` | `ConfirmSignUp` |
204
+ | `lixa.resendConfirmationCode()` | `ResendConfirmationCode` |
205
+ | `lixa.forgotPassword()` | `ForgotPassword` |
206
+ | `lixa.confirmPasswordReset()` | `ConfirmForgotPassword` |
207
+ | `lixa.changePassword()` | `InitiateAuth` → `ChangePassword` |
250
208
 
251
- // 4. PKCE & OAuth Flow State
252
- model OAuthState {
253
- state String @id @map("state")
254
- provider String? @map("provider")
255
- redirectUri String? @map("redirect_uri")
256
- codeVerifier String? @map("code_verifier")
257
- codeChallenge String? @map("code_challenge")
258
- expiresAt DateTime @map("expires_at")
259
- createdAt DateTime @default(now()) @map("created_at")
260
-
261
- @@index([expiresAt])
262
- @@map("oauth_states")
263
- }
264
- ```
209
+ **Features:**
210
+ - Automatic `SecretHash` HMAC-SHA256 computation when `clientSecret` is configured
211
+ - JWT ID token decoding for user profile extraction
212
+ - Cognito error mapping to Lixa error types (`UsernameExistsException` → `UserAlreadyExistsError`, etc.)
213
+ - Custom endpoint support for LocalStack, VPC endpoints, or mock servers
214
+ - Hosted UI federated SSO with automatic provider registration
265
215
 
266
- Push the schema to your database:
267
- ```bash
268
- npx prisma db push
216
+ ### Auth0
217
+
218
+ ```typescript
219
+ import { Auth0IdentityProvider } from "@vunexa/lixa-extensions/identity/auth0";
220
+
221
+ const lixa = new Lixa({
222
+ identity: new Auth0IdentityProvider({
223
+ domain: "your-tenant.auth0.com",
224
+ clientId: process.env.AUTH0_CLIENT_ID!,
225
+ clientSecret: process.env.AUTH0_CLIENT_SECRET,
226
+ connection: "Username-Password-Authentication", // optional
227
+ }),
228
+ });
269
229
  ```
270
230
 
271
- ---
231
+ ### Okta
232
+
233
+ ```typescript
234
+ import { OktaIdentityProvider } from "@vunexa/lixa-extensions/identity/okta";
235
+
236
+ const lixa = new Lixa({
237
+ identity: new OktaIdentityProvider({
238
+ orgUrl: "https://your-org.okta.com",
239
+ clientId: process.env.OKTA_CLIENT_ID,
240
+ apiToken: process.env.OKTA_API_TOKEN, // for admin operations
241
+ }),
242
+ });
243
+ ```
272
244
 
273
- ### Step 2: Initialize Lixa & Storage with 2-Minute Cache
245
+ ### Self-Managed (Database)
274
246
 
275
- Create `src/config/lixa.ts`:
247
+ Use your own database for user credentials — no external identity service needed. Includes Node.js native `crypto.scrypt` hashing, configurable password policies, and timing-attack-safe verification.
276
248
 
277
249
  ```typescript
278
- import { Lixa, CompositeIdentityProvider, AccountLinkingStrategy } from "@vunexa/lixa";
279
- import { CognitoIdentityProvider } from "@vunexa/lixa-extensions/identity";
280
- import { GoogleProvider, GithubProvider } from "@vunexa/lixa-extensions/providers";
250
+ import { Lixa } from "@vunexa/lixa";
281
251
  import { createPrismaAdapter } from "@vunexa/lixa-extensions/storage/prisma";
282
252
  import { PrismaClient } from "@prisma/client";
283
253
 
284
254
  const prisma = new PrismaClient();
255
+ const storage = createPrismaAdapter(prisma);
256
+
257
+ const lixa = new Lixa({
258
+ storage,
259
+ credentials: {
260
+ policy: {
261
+ minLength: 10,
262
+ requireUppercase: true,
263
+ requireNumbers: true,
264
+ requireSpecialChars: true,
265
+ },
266
+ },
267
+ });
268
+ ```
285
269
 
286
- export const lixa = new Lixa({
287
- // 1. Unified storage with automatic 2-minute (120s) in-memory cache
288
- storage: createPrismaAdapter(prisma, {
289
- enableCache: true,
290
- cacheTtlSeconds: 120, // Cache session validations locally
291
- }),
270
+ ### Composite (Multiple Backends)
292
271
 
293
- // 2. Multi-SSO account linking strategy
294
- accountLinking: {
295
- mode: AccountLinkingStrategy.AUTO_LINK_BY_VERIFIED_EMAIL,
296
- requireVerifiedEmail: true,
297
- },
272
+ Combine multiple identity providers under a single Lixa instance:
273
+
274
+ ```typescript
275
+ import { Lixa, CompositeIdentityProvider, SelfManagedIdentityProvider } from "@vunexa/lixa";
276
+ import { CognitoIdentityProvider } from "@vunexa/lixa-extensions/identity/cognito";
277
+ import { GoogleProvider } from "@vunexa/lixa-extensions/providers";
298
278
 
299
- // 3. Composite Identity Provider (AWS Cognito + Social SSO)
279
+ const lixa = new Lixa({
300
280
  identityProvider: new CompositeIdentityProvider({
301
281
  defaultProvider: "cognito",
302
282
  providers: {
303
283
  cognito: new CognitoIdentityProvider({
304
- userPoolId: process.env.COGNITO_USER_POOL_ID!,
305
- clientId: process.env.COGNITO_CLIENT_ID!,
306
- clientSecret: process.env.COGNITO_CLIENT_SECRET, // optional
307
- region: process.env.AWS_REGION || "us-east-1",
308
- domain: process.env.COGNITO_DOMAIN, // e.g. "my-app.auth.us-east-1.amazoncognito.com"
284
+ userPoolId: "us-east-1_xxx",
285
+ clientId: "your-client-id",
286
+ region: "us-east-1",
287
+ }),
288
+ "self-managed": new SelfManagedIdentityProvider({
289
+ /* credentials config */
309
290
  }),
310
291
  },
311
292
  oauthProviders: {
@@ -313,191 +294,427 @@ export const lixa = new Lixa({
313
294
  provider: new GoogleProvider(),
314
295
  clientId: process.env.GOOGLE_CLIENT_ID!,
315
296
  clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
316
- redirectUri: "http://localhost:3000/api/v1/auth/google/callback",
317
- scopes: {
318
- auth: ["openid", "email", "profile"],
319
- resource: ["https://www.googleapis.com/auth/drive.readonly"],
320
- },
321
- },
322
- github: {
323
- provider: new GithubProvider(),
324
- clientId: process.env.GITHUB_CLIENT_ID!,
325
- clientSecret: process.env.GITHUB_CLIENT_SECRET!,
326
- redirectUri: "http://localhost:3000/api/v1/auth/github/callback",
327
- scopes: {
328
- auth: ["read:user", "user:email"],
329
- resource: ["repo", "read:org"],
330
- },
297
+ redirectUri: "http://localhost:3000/auth/google/callback",
298
+ scopes: ["openid", "email", "profile"],
331
299
  },
332
300
  },
333
301
  }),
334
302
  });
303
+
304
+ // Route to a specific backend:
305
+ await lixa.signIn({ identifier: "user@example.com", password: "pass", provider: "cognito" });
335
306
  ```
336
307
 
337
308
  ---
338
309
 
339
- ### Step 3: Setup Express Server & Routes
310
+ ## OAuth / SSO Providers
311
+
312
+ ### Built-in Providers
340
313
 
341
- Create `src/server.ts`:
314
+ Available from `@vunexa/lixa-extensions/providers`:
315
+
316
+ | Provider | Class | Default Auth Scopes |
317
+ |----------|-------|-------------------|
318
+ | Google | `GoogleProvider` | `openid`, `profile`, `email` |
319
+ | GitHub | `GithubProvider` | `read:user`, `user:email` |
320
+ | Microsoft | `MicrosoftProvider` | `openid`, `profile`, `email`, `User.Read` |
321
+ | AWS Cognito SSO | `CognitoSSOProvider` | `openid`, `email`, `profile` |
342
322
 
343
323
  ```typescript
344
- import express from "express";
345
- import cookieParser from "cookie-parser";
346
- import cors from "cors";
347
- import { createAuthRouter, createRequireAuthMiddleware } from "@vunexa/lixa-extensions/http/express";
348
- import { lixa } from "./config/lixa";
349
-
350
- const app = express();
351
- app.use(express.json());
352
- app.use(cookieParser(process.env.COOKIE_SECRET || "super-secret-key"));
353
- app.use(cors({ origin: "http://localhost:5173", credentials: true }));
354
-
355
- // Auth guard middleware
356
- const requireAuth = createRequireAuthMiddleware(lixa);
324
+ import { GoogleProvider, GithubProvider, MicrosoftProvider, CognitoSSOProvider } from "@vunexa/lixa-extensions/providers";
325
+
326
+ const lixa = new Lixa({
327
+ providers: {
328
+ google: {
329
+ provider: new GoogleProvider(),
330
+ clientId: "...", clientSecret: "...", redirectUri: "...",
331
+ scopes: ["openid", "email", "profile"],
332
+ },
333
+ microsoft: {
334
+ provider: new MicrosoftProvider({ tenant: "common" }),
335
+ clientId: "...", clientSecret: "...", redirectUri: "...",
336
+ scopes: ["openid", "profile", "email", "User.Read"],
337
+ },
338
+ },
339
+ });
340
+ ```
341
+
342
+ ### Custom Providers
343
+
344
+ Integrate **any** OAuth 2.0 / OIDC provider by implementing the `IProvider` interface — just 3 URLs:
357
345
 
358
- // Mount Lixa authentication routes:
359
- // - GET /api/v1/auth/login?provider=cognito
360
- // - GET /api/v1/auth/callback
361
- // - POST /api/v1/auth/logout
362
- // - GET /api/v1/auth/me
363
- const authRouter = express.Router();
364
- createAuthRouter(lixa, {
365
- router: authRouter,
366
- requireAuth,
367
- successRedirectUrl: "http://localhost:5173/dashboard",
368
- errorRedirectUrl: "http://localhost:5173/login?error=auth_failed",
346
+ ```typescript
347
+ import { type IProvider, Lixa } from "@vunexa/lixa";
348
+
349
+ const discordProvider: IProvider = {
350
+ authorizationEndpoint: "https://discord.com/api/oauth2/authorize",
351
+ tokenEndpoint: "https://discord.com/api/oauth2/token",
352
+ userInfoEndpoint: "https://discord.com/api/users/@me",
353
+ };
354
+
355
+ const lixa = new Lixa({
356
+ providers: {
357
+ discord: {
358
+ provider: discordProvider,
359
+ clientId: "...", clientSecret: "...", redirectUri: "...",
360
+ scopes: ["identify", "email"],
361
+ },
362
+ },
369
363
  });
370
- app.use("/api/v1/auth", authRouter);
371
364
  ```
372
365
 
373
366
  ---
374
367
 
375
- ### Step 4: Protect Routes & Use Tokens
368
+ ## Credentials Authentication
369
+
370
+ Sign up, sign in, change password, and forgot password — all through a unified API:
376
371
 
377
372
  ```typescript
378
- // Protected route example
379
- app.get("/api/v1/profile", requireAuth, async (req: any, res) => {
380
- // req.session is populated automatically
381
- const { userId, email, provider, accessToken, idToken } = req.session;
382
-
383
- res.json({
384
- message: "Authenticated successfully!",
385
- user: {
386
- userId,
387
- email,
388
- provider,
389
- },
390
- tokens: {
391
- accessTokenPreview: accessToken ? `${accessToken.substring(0, 15)}...` : null,
392
- idTokenPreview: idToken ? `${idToken.substring(0, 15)}...` : null,
393
- },
394
- });
373
+ // Sign up a new user
374
+ const { user, sessionId } = await lixa.signUp({
375
+ identifier: "alice@example.com",
376
+ password: "SecurePassword123!",
377
+ email: "alice@example.com",
378
+ metadata: { name: "Alice Smith" },
379
+ });
380
+
381
+ // Sign in
382
+ const { user, sessionId, session } = await lixa.signIn({
383
+ identifier: "alice@example.com",
384
+ password: "SecurePassword123!",
385
+ });
386
+
387
+ // Change password
388
+ await lixa.changePassword({
389
+ identifier: "alice@example.com",
390
+ oldPassword: "SecurePassword123!",
391
+ newPassword: "NewSecurePassword456!",
392
+ });
393
+
394
+ // Forgot password flow
395
+ const { deliveryMedium } = await lixa.forgotPassword({
396
+ identifier: "alice@example.com",
397
+ });
398
+
399
+ // Confirm password reset with verification code
400
+ await lixa.confirmPasswordReset({
401
+ identifier: "alice@example.com",
402
+ confirmationCode: "123456",
403
+ newPassword: "ResetPassword789!",
395
404
  });
396
405
 
397
- app.listen(3000, () => {
398
- console.log("Server running at http://localhost:3000");
406
+ // Verify credentials without creating a session
407
+ const identity = await lixa.verifyCredentials({
408
+ identifier: "alice@example.com",
409
+ password: "ResetPassword789!",
399
410
  });
400
411
  ```
401
412
 
402
413
  ---
403
414
 
404
- ## 🔌 Connecting External Resources (AuthZ)
415
+ ## Session Management
416
+
417
+ Lixa manages sessions with pluggable storage. By default, sessions are stored in-memory (suitable for development). For production, use a database adapter.
418
+
419
+ ```typescript
420
+ // Fetch session info
421
+ const session = await lixa.fetchSessionInfo(sessionId);
422
+ // → { sessionId, userId, email, provider, token, raw }
423
+
424
+ // Delete session (logout)
425
+ await lixa.deleteSession(sessionId);
426
+ ```
427
+
428
+ **Cookie utilities** are included for secure session cookie management:
429
+
430
+ ```typescript
431
+ import {
432
+ createSessionCookie,
433
+ clearSessionCookie,
434
+ DEFAULT_SESSION_COOKIE_NAME,
435
+ } from "@vunexa/lixa";
436
+
437
+ // Create a session cookie (HttpOnly, Secure, SameSite=Lax)
438
+ const cookie = createSessionCookie(sessionId);
439
+ // → { name: "lixa_session", value: sessionId, options: { httpOnly, secure, ... } }
440
+ ```
441
+
442
+ ---
443
+
444
+ ## Account Linking
405
445
 
406
- Unlike login authentication, **Resource Connections** allow your application to interact with external APIs (like GitHub repositories or Google Drive files) on behalf of the user.
446
+ Automatically link multiple SSO accounts (Google + GitHub + Cognito) under a single user identity based on verified email:
407
447
 
408
448
  ```typescript
409
- // 1. Generate connection redirect URL
410
- app.get("/api/v1/resources/github/connect", requireAuth, async (req: any, res) => {
411
- const url = await lixa.getResourceAuthUrl("github", {
412
- userId: req.session.userId,
413
- redirectUri: "http://localhost:3000/api/v1/resources/github/callback",
414
- });
415
- res.redirect(url);
449
+ import { Lixa, AccountLinkingStrategy } from "@vunexa/lixa";
450
+
451
+ const lixa = new Lixa({
452
+ accountLinking: {
453
+ mode: AccountLinkingStrategy.AUTO_LINK_BY_VERIFIED_EMAIL,
454
+ requireVerifiedEmail: true, // default
455
+ },
456
+ providers: { /* ... */ },
416
457
  });
458
+ ```
459
+
460
+ **Account linking strategies:**
461
+
462
+ | Strategy | Behavior |
463
+ |----------|----------|
464
+ | `AUTO_LINK_BY_VERIFIED_EMAIL` | Auto-merge accounts with the same verified email |
465
+ | `ISOLATED` | Keep each provider login as a separate account (default) |
466
+ | `STEP_UP_VERIFICATION` | Require password verification before linking a new provider |
467
+
468
+ **Manual account linking:**
469
+
470
+ ```typescript
471
+ // Explicitly link a provider to an active session
472
+ await lixa.linkAccount({ sessionId, provider: "github", code, state });
417
473
 
418
- // 2. Handle resource callback & store token
419
- app.get("/api/v1/resources/github/callback", requireAuth, async (req: any, res) => {
420
- const { code } = req.query;
421
- await lixa.handleResourceCallback("github", code as string, req.session.userId);
422
- res.redirect("http://localhost:5173/settings?connected=github");
474
+ // Unlink a provider
475
+ await lixa.unlinkAccount(sessionId, "github");
476
+
477
+ // Get all linked accounts for a user
478
+ const accounts = await lixa.getUserAccounts(sessionId);
479
+ // → { google: { provider, email, linkedAt }, github: { ... } }
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Resource Connections (AuthZ)
485
+
486
+ Connect third-party APIs (Google Drive, GitHub Repos) **post-login** with clean AuthN / AuthZ separation:
487
+
488
+ ```typescript
489
+ // Configure scopes for resource authorization
490
+ const lixa = new Lixa({
491
+ providers: {
492
+ github: {
493
+ provider: new GithubProvider(),
494
+ clientId: "...", clientSecret: "...", redirectUri: "...",
495
+ scopes: {
496
+ auth: ["read:user", "user:email"], // login scopes
497
+ resource: ["repo", "read:org"], // post-login API scopes
498
+ },
499
+ },
500
+ },
423
501
  });
424
502
 
425
- // 3. Make third-party API calls using stored resource tokens
426
- app.get("/api/v1/resources/github/repos", requireAuth, async (req: any, res) => {
427
- const resource = await lixa.getResource(req.session.userId, "github");
428
- if (!resource) {
429
- return res.status(404).json({ error: "GitHub account not connected" });
430
- }
503
+ // 1. Generate resource auth URL (user must be logged in)
504
+ const resourceUrl = await lixa.getResourceAuthUrl({
505
+ sessionId,
506
+ provider: "github",
507
+ scopes: ["repo", "read:org"],
508
+ prompt: "consent",
509
+ });
431
510
 
432
- // Call GitHub API with resource.accessToken
433
- const response = await fetch("https://api.github.com/user/repos", {
434
- headers: { Authorization: `Bearer ${resource.accessToken}` },
435
- });
436
- const repos = await response.json();
437
- res.json({ repos });
511
+ // 2. Handle resource callback
512
+ const session = await lixa.handleResourceCallback({
513
+ sessionId,
514
+ provider: "github",
515
+ code: "auth_code",
516
+ state: "state_param",
438
517
  });
518
+
519
+ // 3. Get connected resource token (auto-refreshes expired tokens)
520
+ const resource = await lixa.getConnectedResource(sessionId, "github");
521
+ // → { provider, accessToken, refreshToken, expiresAt, scopes, raw }
522
+
523
+ // 4. Or fetch by user ID directly (session-independent)
524
+ const resource = await lixa.getUserResource("user@example.com", "github");
525
+
526
+ // 5. Disconnect a resource
527
+ await lixa.disconnectResource(sessionId, "github");
439
528
  ```
440
529
 
441
530
  ---
442
531
 
443
- ## ⚡ In-Memory 2-Minute Caching (`withLocalCache`)
532
+ ## Database Storage
444
533
 
445
- Under high traffic, hitting your database on every single API request to validate a session creates heavy I/O bottlenecks.
446
-
447
- Lixa includes a high-performance **2-Minute In-Memory TTL Cache**:
534
+ Lixa uses in-memory storage by default. For production, use the database adapters from `@vunexa/lixa-extensions`:
448
535
 
449
536
  ```typescript
450
- import { withLocalCache } from "@vunexa/lixa-extensions/storage";
537
+ // Prisma
538
+ import { createPrismaAdapter } from "@vunexa/lixa-extensions/storage/prisma";
539
+ const storage = createPrismaAdapter(new PrismaClient());
540
+
541
+ // Drizzle
542
+ import { createDrizzleAdapter } from "@vunexa/lixa-extensions/storage/drizzle";
543
+ const storage = createDrizzleAdapter(db, {
544
+ sessions: schema.sessions,
545
+ userResources: schema.userResources,
546
+ oauthStates: schema.oauthStates,
547
+ userCredentials: schema.userCredentials,
548
+ });
451
549
 
452
- // Automatically applied when using createPrismaAdapter
453
- const cachedStorage = withLocalCache(baseAdapter, {
454
- ttlSeconds: 120, // 2 minutes (default)
550
+ // Pass to Lixa
551
+ const lixa = new Lixa({
552
+ storage,
553
+ providers: { /* ... */ },
455
554
  });
456
555
  ```
457
556
 
458
- ### Cache Features & Invalidation Guarantees:
459
- - **Zero Database I/O**: Session lookups within 120 seconds return in sub-millisecond memory time.
460
- - **Auto-Invalidation on Logout**: Calling `deleteSession(sessionId)` immediately clears both the database record and memory cache.
461
- - **Auto-Invalidation on Updates**: Saving or updating accounts/credentials purges stale cached keys automatically.
462
- - **Safe Isolation**: OAuth states (single-use CSRF tokens) bypass the cache and validate directly against persistent storage.
557
+ The adapters include a built-in **2-minute in-memory TTL cache** to eliminate redundant database reads on rapid HTTP requests. Disable it with `{ enableCache: false }` (Prisma) or by not calling `withLocalCache`.
463
558
 
464
559
  ---
465
560
 
466
- ## 🌐 Supported Identity Providers
561
+ ## Express Integration
562
+
563
+ Drop-in Express route handlers and middleware from `@vunexa/lixa-extensions/express`:
467
564
 
468
- | Provider | Type | AuthN (SSO) | AuthZ (Resources) | Package |
469
- | :--- | :--- | :---: | :---: | :--- |
470
- | **AWS Cognito** | Enterprise IdP | ✅ | — | `@vunexa/lixa-extensions/identity` |
471
- | **Google** | Social / OIDC | ✅ | ✅ (Drive, Gmail) | `@vunexa/lixa-extensions/providers` |
472
- | **GitHub** | OAuth 2.0 | ✅ | ✅ (Repos, Orgs) | `@vunexa/lixa-extensions/providers` |
473
- | **Microsoft** | Azure AD / OIDC | ✅ | ✅ (Graph API) | `@vunexa/lixa-extensions/providers` |
474
- | **Auth0** | Enterprise IdP | ✅ | — | `@vunexa/lixa-extensions/identity` |
475
- | **Okta** | Enterprise IdP | ✅ | — | `@vunexa/lixa-extensions/identity` |
476
- | **Self-Managed** | SQLite / Postgres | ✅ | — | `@vunexa/lixa` (Built-in) |
565
+ ```typescript
566
+ import {
567
+ handleLogin,
568
+ handleCallback,
569
+ handleLogout,
570
+ createRequireAuthMiddleware,
571
+ handleCredentialsSignUp,
572
+ handleCredentialsSignIn,
573
+ } from "@vunexa/lixa-extensions/express";
574
+
575
+ const requireAuth = createRequireAuthMiddleware(lixa);
576
+
577
+ // OAuth SSO
578
+ app.get("/login", (req, res) => handleLogin(req, res, lixa));
579
+ app.get("/auth/:provider/callback", (req, res) =>
580
+ handleCallback(req, res, lixa, {
581
+ successRedirectUrl: "/dashboard",
582
+ errorRedirectUrl: "/login?error=auth_failed",
583
+ })
584
+ );
585
+
586
+ // Credentials (username/password)
587
+ app.post("/auth/signup", (req, res) => handleCredentialsSignUp(req, res, lixa));
588
+ app.post("/auth/signin", (req, res) => handleCredentialsSignIn(req, res, lixa));
589
+
590
+ // Protected routes
591
+ app.get("/profile", requireAuth, (req, res) => {
592
+ res.json({ user: req.sessionInfo });
593
+ });
594
+
595
+ // Logout
596
+ app.post("/logout", (req, res) => handleLogout(req, res, lixa));
597
+ ```
477
598
 
478
599
  ---
479
600
 
480
- ## 📚 TypeScript API Reference
601
+ ## Error Handling
481
602
 
482
- ### `new Lixa(options)`
483
- - `storage`: Storage adapter created via `createPrismaAdapter` or custom implementation.
484
- - `identityProvider`: `CompositeIdentityProvider` or standalone IdP instance.
485
- - `accountLinking`: Configuration for cross-provider email matching (`AccountLinkingStrategy.AUTO_LINK_BY_VERIFIED_EMAIL`).
486
- - `sessionHandler`: Custom session serialization logic (optional).
603
+ All Lixa errors extend `LixaError` with a `code` and optional `details`:
487
604
 
488
- ### Methods
489
- - `lixa.getAuthUrl(provider, options)`: Returns authorization URL with PKCE verifier stored in state.
490
- - `lixa.handleCallback(provider, code, state)`: Validates state, exchanges code for tokens, creates session, and links account.
491
- - `lixa.getSession(sessionId)`: Retrieves active session from memory cache or database.
492
- - `lixa.deleteSession(sessionId)`: Deletes session and purges local cache.
493
- - `lixa.getResourceAuthUrl(provider, options)`: Returns resource authorization URL.
494
- - `lixa.handleResourceCallback(provider, code, userId)`: Stores connected resource tokens under `userId`.
495
- - `lixa.getResource(userId, provider)`: Retrieves active resource token for third-party API requests.
605
+ ```typescript
606
+ import {
607
+ LixaError,
608
+ InvalidCredentialsError,
609
+ UserAlreadyExistsError,
610
+ WeakPasswordError,
611
+ ProviderNotConfiguredError,
612
+ SessionNotFoundError,
613
+ AccountLinkingChallengeRequiredError,
614
+ } from "@vunexa/lixa";
615
+
616
+ try {
617
+ await lixa.signIn({ identifier: "user", password: "wrong" });
618
+ } catch (error) {
619
+ if (error instanceof InvalidCredentialsError) {
620
+ // error.code === "INVALID_CREDENTIALS"
621
+ }
622
+ if (error instanceof WeakPasswordError) {
623
+ // error.validationErrors === ["Must be at least 10 characters", ...]
624
+ }
625
+ if (error instanceof AccountLinkingChallengeRequiredError) {
626
+ // error.challengeToken, error.email, error.existingProviders
627
+ }
628
+ }
629
+ ```
630
+
631
+ **Error codes reference:**
632
+
633
+ | Error Class | Code | When |
634
+ |-------------|------|------|
635
+ | `InvalidStateError` | `INVALID_STATE` | OAuth state expired or tampered |
636
+ | `ProviderNotConfiguredError` | `PROVIDER_NOT_CONFIGURED` | Provider not in config |
637
+ | `InvalidProviderConfigError` | `INVALID_PROVIDER_CONFIG` | Missing clientId/secret/redirectUri |
638
+ | `TokenExchangeError` | `TOKEN_EXCHANGE_FAILED` | Code-to-token exchange failed |
639
+ | `SessionNotFoundError` | `SESSION_NOT_FOUND` | Session expired or invalid |
640
+ | `InvalidCredentialsError` | `INVALID_CREDENTIALS` | Wrong username/password |
641
+ | `UserAlreadyExistsError` | `USER_ALREADY_EXISTS` | Duplicate registration |
642
+ | `UserNotFoundError` | `USER_NOT_FOUND` | User not in database |
643
+ | `WeakPasswordError` | `WEAK_PASSWORD` | Password policy violation |
644
+ | `IdentityNotConfiguredError` | `CREDENTIALS_NOT_CONFIGURED` | No identity provider set |
645
+ | `AccountLinkingChallengeRequiredError` | `ACCOUNT_LINKING_CHALLENGE_REQUIRED` | Step-up verification needed |
646
+ | `SSOAccountAlreadyExistsError` | `SSO_ACCOUNT_EXISTS` | Email already has SSO account |
647
+ | `AccountNotVerifiedError` | `ACCOUNT_NOT_VERIFIED` | Email not confirmed yet |
648
+ | `RefreshTokenError` | `REFRESH_TOKEN_ERROR` | Token refresh failed |
496
649
 
497
650
  ---
498
651
 
499
- ## 🤝 Contributing & License
652
+ ## API Reference
653
+
654
+ ### `Lixa` Class
655
+
656
+ **Constructor:** `new Lixa(config: LixaConfig)`
657
+
658
+ | Config Property | Type | Description |
659
+ |----------------|------|-------------|
660
+ | `providers` | `Record<string, ProviderConfig>` | OAuth provider configurations |
661
+ | `identityProvider` / `identity` | `IIdentityProvider \| IdentityConfig` | Identity backend (Cognito, Auth0, Okta, Self-Managed) |
662
+ | `credentials` | `CredentialsConfig` | Self-managed credential settings (auto-creates SelfManagedIdentityProvider) |
663
+ | `storage` | `StorageAdapter` | Unified database adapter (Prisma / Drizzle) |
664
+ | `accountLinking` | `boolean \| AccountLinkingMode \| AccountLinkingConfig` | Multi-SSO account linking strategy |
665
+ | `sessionCookieName` | `string \| ((lixa, req?) => string)` | Custom session cookie name |
666
+ | `debug` | `boolean` | Enable structured debug logging |
667
+ | `logger` | `LixaLogger` | Custom logger implementation |
668
+
669
+ **OAuth Methods:**
670
+
671
+ | Method | Returns | Description |
672
+ |--------|---------|-------------|
673
+ | `getAuthUrl(provider, state?)` | `Promise<string>` | Generate authorization URL with PKCE |
674
+ | `handleCallback({ provider, code, state })` | `Promise<string>` | Exchange code for tokens, create session |
675
+ | `isProviderConfigured(provider)` | `boolean` | Check if a provider is configured |
676
+
677
+ **Identity Methods:**
678
+
679
+ | Method | Returns | Description |
680
+ |--------|---------|-------------|
681
+ | `signUp(params)` | `Promise<SignUpResult>` | Register a new user |
682
+ | `signIn(params)` | `Promise<SignInResult>` | Authenticate with credentials |
683
+ | `verifyCredentials(params)` | `Promise<UserIdentity \| null>` | Verify credentials without session |
684
+ | `changePassword(params)` | `Promise<boolean>` | Update user password |
685
+ | `forgotPassword(params)` | `Promise<ForgotPasswordResult>` | Initiate password reset |
686
+ | `confirmPasswordReset(params)` | `Promise<boolean>` | Complete password reset |
687
+ | `confirmSignUp(params)` | `Promise<boolean>` | Confirm registration with code |
688
+ | `resendConfirmationCode(params)` | `Promise<ResendConfirmationCodeResult>` | Resend verification code |
689
+
690
+ **Session & Account Methods:**
691
+
692
+ | Method | Returns | Description |
693
+ |--------|---------|-------------|
694
+ | `fetchSessionInfo(sessionId)` | `Promise<Session \| null>` | Get active session details |
695
+ | `deleteSession(sessionId)` | `Promise<void>` | Delete session (logout) |
696
+ | `linkAccount(params)` | `Promise<string>` | Link new OAuth provider to session |
697
+ | `unlinkAccount(sessionId, provider)` | `Promise<boolean>` | Unlink a provider account |
698
+ | `getUserAccounts(userIdOrSessionId)` | `Promise<Record<string, LinkedAccount>>` | Get all linked accounts |
699
+
700
+ **Resource Methods:**
701
+
702
+ | Method | Returns | Description |
703
+ |--------|---------|-------------|
704
+ | `getResourceAuthUrl(params)` | `Promise<string>` | Generate resource authorization URL |
705
+ | `handleResourceCallback(params)` | `Promise<Session>` | Handle resource OAuth callback |
706
+ | `getConnectedResource(sessionId, provider)` | `Promise<ConnectedResource \| null>` | Get resource token (auto-refreshes) |
707
+ | `getUserResource(userId, provider)` | `Promise<ConnectedResource \| null>` | Get resource by user ID |
708
+ | `disconnectResource(sessionId, provider)` | `Promise<boolean>` | Disconnect resource provider |
709
+
710
+ **Static Methods:**
711
+
712
+ | Method | Returns | Description |
713
+ |--------|---------|-------------|
714
+ | `Lixa.generateRandomState()` | `string` | Generate 32-char hex CSRF state |
715
+
716
+ ---
500
717
 
501
- Contributions are welcome! Please open an issue or pull request on GitHub.
718
+ ## License
502
719
 
503
- Distributed under the **MIT License**. See `LICENSE` for details.
720
+ [MIT](https://opensource.org/licenses/MIT) © [Vunexa](https://vunexa.app)