@soapjs/soap-auth 0.2.0 → 0.3.0
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 +100 -616
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,679 +1,163 @@
|
|
|
1
|
-
# SoapAuth - Authentication
|
|
1
|
+
# SoapAuth - Modular Authentication Solution
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
1. [Introduction](#introduction)
|
|
6
|
-
- [What is `SoapAuth`?](#what-is-soapauth)
|
|
7
|
-
- [Key Features](#key-features)
|
|
8
|
-
- [Supported Authentication Strategies](#supported-authentication-strategies)
|
|
9
|
-
- [When to Use `SoapAuth`](#when-to-use-soapauth)
|
|
10
|
-
|
|
11
|
-
2. [Installation & Setup](#installation--setup)
|
|
12
|
-
- [Prerequisites](#prerequisites)
|
|
13
|
-
- [Installing `soap-auth`](#installing-soap-auth)
|
|
14
|
-
- [Basic Configuration](#basic-configuration)
|
|
15
|
-
|
|
16
|
-
3. [Core Concepts](#core-concepts)
|
|
17
|
-
- [Authentication Strategies (`AuthStrategy`)](#authentication-strategies-authstrategy)
|
|
18
|
-
- [`SoapAuth` Core Class Overview](#soapauth-core-class-overview)
|
|
19
|
-
- [How Strategies Work with `SoapAuth`](#how-strategies-work-with-soapauth)
|
|
20
|
-
- [HTTP vs. WebSocket Authentication](#http-vs-websocket-authentication)
|
|
21
|
-
|
|
22
|
-
4. [Implementing Strategies](#implementing-strategies)
|
|
23
|
-
|
|
24
|
-
<!-- WIP
|
|
25
|
-
5. [Using `SoapAuth` in Different Environments](#using-soapauth-in-different-environments)
|
|
26
|
-
- [Express.js Integration](#expressjs-integration)
|
|
27
|
-
- [Middleware Setup](#middleware-setup)
|
|
28
|
-
- [Protecting Routes](#protecting-routes)
|
|
29
|
-
- [Example: Authenticating Requests in Express](#example-authenticating-requests-in-express)
|
|
30
|
-
- [WebSocket Authentication](#websocket-authentication)
|
|
31
|
-
- [How WebSocket Authentication Works](#how-websocket-authentication-works)
|
|
32
|
-
- [Example: Securing WebSocket Connections](#example-securing-websocket-connections)
|
|
33
|
-
- [GraphQL Authentication](#graphql-authentication)
|
|
34
|
-
- [Using `SoapAuth` with Apollo Server](#using-soapauth-with-apollo-server)
|
|
35
|
-
- [Example: Adding Authentication to GraphQL Resolvers](#example-adding-authentication-to-graphql-resolvers)
|
|
36
|
-
- [Microservices & External APIs](#microservices--external-apis)
|
|
37
|
-
- [Using `SoapAuth` for Microservices](#using-soapauth-for-microservices)
|
|
38
|
-
- [Example: Validating API Requests from External Services](#example-validating-api-requests-from-external-services)
|
|
39
|
-
|
|
40
|
-
6. [Advanced Usage](#advanced-usage)
|
|
41
|
-
- [Handling Multiple Strategies Simultaneously](#handling-multiple-strategies-simultaneously)
|
|
42
|
-
- [Refreshing Tokens and Session Management](#refreshing-tokens-and-session-management)
|
|
43
|
-
- [Logging and Error Handling](#logging-and-error-handling) -->
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
## 1️. Introduction
|
|
47
|
-
|
|
48
|
-
### What is `SoapAuth`?
|
|
49
|
-
|
|
50
|
-
`SoapAuth` is a **flexible authentication strategy manager** and one of the core modules of `@soapjs` – a toolkit for building clean architecture-based applications efficiently.
|
|
51
|
-
|
|
52
|
-
It provides a **structured and extensible approach** to authentication, allowing developers to manage multiple authentication strategies across different environments, including **HTTP APIs (Express.js), WebSockets, GraphQL, and microservices**.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
With `SoapAuth`, you can:
|
|
56
|
-
|
|
57
|
-
- Easily **add, remove, and switch authentication strategies** dynamically.
|
|
58
|
-
- Support **OAuth2, JWT, API Keys, and custom authentication strategies**.
|
|
59
|
-
- Use it in **Express.js, WebSockets, GraphQL, and microservices**.
|
|
60
|
-
- Handle **token refresh, session management, and error handling** efficiently.
|
|
61
|
-
|
|
62
|
-
### Key Features
|
|
63
|
-
|
|
64
|
-
✔ **Multi-strategy support** – Use different authentication methods within the same application.
|
|
65
|
-
✔ **Modular and extensible** – Easily add new authentication strategies.
|
|
66
|
-
✔ **Works with HTTP & WebSockets** – Supports both request-based and persistent connection authentication.
|
|
67
|
-
✔ **Easy integration** – Plug it into Express, WebSockets, GraphQL, or any custom API.
|
|
68
|
-
✔ **Dynamic management** – Add, remove, or update authentication strategies at runtime.
|
|
69
|
-
✔ **Built-in logging and debugging** – Helps troubleshoot authentication issues.
|
|
70
|
-
|
|
71
|
-
### Supported Authentication Strategies
|
|
72
|
-
|
|
73
|
-
| Strategy Type | Description |
|
|
74
|
-
|--------------------|------------|
|
|
75
|
-
| **OAuth2** | Authenticate users via external providers like Google, Facebook, or GitHub. |
|
|
76
|
-
| **JWT (JSON Web Token)** | Secure API endpoints with token-based authentication. |
|
|
77
|
-
| **API Key** | Use API keys for authentication in RESTful services. |
|
|
78
|
-
| **Custom Strategies** | Define your own authentication mechanisms based on your needs. |
|
|
79
|
-
|
|
80
|
-
### When to Use `SoapAuth`?
|
|
81
|
-
|
|
82
|
-
Use `SoapAuth` if you need:
|
|
83
|
-
|
|
84
|
-
- **Multiple authentication methods** in your application (e.g., JWT for API + OAuth2 for users).
|
|
85
|
-
- **A structured way** to manage authentication across different request types (HTTP, WebSockets).
|
|
86
|
-
- **Flexibility to swap authentication methods** without modifying business logic.
|
|
87
|
-
- **Easy expansion** with custom authentication strategies.
|
|
88
|
-
|
|
89
|
-
## 2️. Installation & Setup
|
|
90
|
-
|
|
91
|
-
### Prerequisites
|
|
92
|
-
|
|
93
|
-
Before installing `soap-auth`, ensure you have the following:
|
|
94
|
-
|
|
95
|
-
- **Node.js** (v16+ recommended)
|
|
96
|
-
- **TypeScript** (optional but recommended for type safety)
|
|
97
|
-
- **A package manager** (`npm`, `yarn`, or `pnpm`)
|
|
98
|
-
|
|
99
|
-
### Installing `soap-auth`
|
|
100
|
-
|
|
101
|
-
You can install `soap-auth` using your preferred package manager:
|
|
3
|
+
SoapAuth is a flexible library for handling authentication and identity management. It allows you to easily implement various authentication strategies such as JWT, OAuth2, Basic Auth, Local Auth, API Key, and more. As part of the **@soapjs** ecosystem, it can be easily extended with additional components like **soap**, **soap-express**, and **soap-cli**.
|
|
102
4
|
|
|
5
|
+
## Installation
|
|
103
6
|
```sh
|
|
104
|
-
# Using npm
|
|
105
7
|
npm install @soapjs/soap-auth
|
|
106
|
-
|
|
107
|
-
# Using yarn
|
|
108
|
-
yarn add @soapjs/soap-auth
|
|
109
|
-
|
|
110
|
-
# Using pnpm
|
|
111
|
-
pnpm add @soapjs/soap-auth
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Basic Configuration
|
|
115
|
-
|
|
116
|
-
`soap-auth` serves as the **core authentication manager** within the `@soapjs` ecosystem. It provides a **framework-agnostic foundation** for authentication strategies and is designed to be extended for use in specific frameworks like Express, WebSockets, and others.
|
|
117
|
-
|
|
118
|
-
To start using `soap-auth`, you need to configure it with authentication strategies.
|
|
119
|
-
|
|
120
|
-
#### **1️. Import `SoapAuth` and Define Strategies**
|
|
121
|
-
Create an `auth.ts` file where you initialize `SoapAuth` with the authentication strategies you plan to use.
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
import { SoapAuth } from "@soapjs/soap-auth";
|
|
125
|
-
import { OAuth2Strategy, JwtStrategy } from "@soapjs/soap-auth";
|
|
126
|
-
|
|
127
|
-
const soapAuth = new SoapAuth({
|
|
128
|
-
strategies: {
|
|
129
|
-
http: {
|
|
130
|
-
oauth2: new OAuth2Strategy({
|
|
131
|
-
clientId: "your-client-id",
|
|
132
|
-
clientSecret: "your-client-secret",
|
|
133
|
-
endpoints: {
|
|
134
|
-
authorizationUrl: "https://provider.com/oauth/authorize",
|
|
135
|
-
tokenUrl: "https://provider.com/oauth/token",
|
|
136
|
-
userInfoUrl: "https://provider.com/userinfo",
|
|
137
|
-
},
|
|
138
|
-
}),
|
|
139
|
-
jwt: new JwtStrategy({
|
|
140
|
-
accessToken: {
|
|
141
|
-
issuer: {
|
|
142
|
-
secretKey: "your-jwt-secret",
|
|
143
|
-
options: {
|
|
144
|
-
issuer: "your-app",
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
routes: {
|
|
149
|
-
login: { path: "your-login-path" method: "POST" },
|
|
150
|
-
logout: { path: "your-logout-path" method: "POST" },
|
|
151
|
-
...
|
|
152
|
-
},
|
|
153
|
-
}),
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
logger: console, // Optional logging
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
export default soapAuth;
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
#### **2️. Initialize Strategies**
|
|
163
|
-
Before using authentication, ensure all strategies are properly initialized.
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
await soapAuth.init();
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
#### **3️. Authenticating Requests**
|
|
170
|
-
To authenticate a request using a specific strategy:
|
|
171
|
-
|
|
172
|
-
```ts
|
|
173
|
-
const authResult = await soapAuth.authenticate("http", "jwt", request);
|
|
174
|
-
console.log(authResult.user);
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Framework-Specific Implementations
|
|
178
|
-
|
|
179
|
-
`soap-auth` serves as the **foundation** for authentication in multiple environments. Specific implementations for frameworks like **Express.js, WebSockets, and GraphQL** are built on top of it.
|
|
180
|
-
|
|
181
|
-
If you're using a specific framework, consider installing its dedicated package:
|
|
182
|
-
|
|
183
|
-
```sh
|
|
184
|
-
# Express.js soap package (WIP)
|
|
185
|
-
npm install @soapjs/soap-express
|
|
186
|
-
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
These packages extend `soap-auth`, providing **plug-and-play middleware** for authentication in framework-specific contexts.
|
|
190
|
-
|
|
191
|
-
## 3️. Core Concepts
|
|
192
|
-
|
|
193
|
-
### Authentication Strategies (`AuthStrategy`)
|
|
194
|
-
|
|
195
|
-
At the core of `soap-auth` is the concept of **authentication strategies**, which define how authentication should be performed. Each strategy is responsible for:
|
|
196
|
-
|
|
197
|
-
- Extracting credentials or tokens from the request.
|
|
198
|
-
- Validating the provided credentials.
|
|
199
|
-
- Returning an authenticated user or rejecting the request.
|
|
200
|
-
|
|
201
|
-
Examples of authentication strategies include **OAuth2, JWT, API Keys, and custom strategies**.
|
|
202
|
-
|
|
203
|
-
### `SoapAuth` Core Class Overview
|
|
204
|
-
|
|
205
|
-
The `SoapAuth` class serves as the **authentication manager**, handling multiple authentication strategies within an application. It allows developers to:
|
|
206
|
-
|
|
207
|
-
- **Register authentication strategies** dynamically.
|
|
208
|
-
- **Manage authentication across different layers** (HTTP, WebSockets, GraphQL, etc.).
|
|
209
|
-
- **Authenticate requests** using specific strategies.
|
|
210
|
-
- **Handle token storage, session management, and error handling**.
|
|
211
|
-
|
|
212
|
-
### How Strategies Work with `SoapAuth`
|
|
213
|
-
|
|
214
|
-
1. **A user sends a request** (e.g., HTTP request, WebSocket connection).
|
|
215
|
-
2. **`SoapAuth` selects the appropriate strategy** based on the request context.
|
|
216
|
-
3. **The selected strategy authenticates the request** by validating tokens, credentials, or API keys.
|
|
217
|
-
4. **If authentication succeeds, the user is granted access**; otherwise, an error is returned.
|
|
218
|
-
|
|
219
|
-
### HTTP vs. WebSocket Authentication
|
|
220
|
-
|
|
221
|
-
| Feature | HTTP Authentication | WebSocket Authentication |
|
|
222
|
-
|---------|----------------------|--------------------------|
|
|
223
|
-
| Request Type | One-time requests | Persistent connection |
|
|
224
|
-
| Example Strategies | OAuth2, JWT, API Key | Token-based, session-based |
|
|
225
|
-
| Validation | Per request | On connection + periodic checks |
|
|
226
|
-
|
|
227
|
-
- **For HTTP**, authentication is performed **on each request**.
|
|
228
|
-
- **For WebSockets**, authentication happens **once on connection** and may include **token refresh checks** during the session.
|
|
229
|
-
|
|
230
|
-
Understanding these differences helps in choosing the right strategy for your use case.
|
|
231
|
-
|
|
232
|
-
## 4️. Implementing Strategies
|
|
233
|
-
|
|
234
|
-
### Built-in Authentication Strategies
|
|
235
|
-
|
|
236
|
-
`soap-auth` provides built-in support for multiple authentication strategies:
|
|
237
|
-
|
|
238
|
-
1. **Basic Authentication** - Username & password via HTTP headers.
|
|
239
|
-
2. **Local Authentication** - Custom credential-based authentication.
|
|
240
|
-
3. **API Key Authentication** - Secure access using an API key.
|
|
241
|
-
4. **JWT Authentication** - Token-based authentication using JSON Web Tokens.
|
|
242
|
-
5. **OAuth2 Authentication** - Third-party authentication with OAuth2 providers.
|
|
243
|
-
|
|
244
|
-
Each strategy is **configurable** and can be **easily extended** or **customized**.
|
|
245
|
-
|
|
246
|
-
### **Basic Authentication (Username & Password)**
|
|
247
|
-
Basic authentication works by extracting credentials from an `Authorization` header.
|
|
248
|
-
|
|
249
|
-
```ts
|
|
250
|
-
import { BasicStrategy } from "@soapjs/soap-auth/strategies/basic.strategy";
|
|
251
|
-
|
|
252
|
-
const basicAuth = new BasicStrategy({
|
|
253
|
-
credentials: {
|
|
254
|
-
extractCredentials: (context) => {
|
|
255
|
-
const authHeader = context.headers?.authorization;
|
|
256
|
-
if (!authHeader || !authHeader.startsWith("Basic ")) return null;
|
|
257
|
-
const decoded = Buffer.from(authHeader.substring(6), "base64").toString();
|
|
258
|
-
const [username, password] = decoded.split(":");
|
|
259
|
-
return { identifier: username, password };
|
|
260
|
-
},
|
|
261
|
-
verifyCredentials: async (username, password) => {
|
|
262
|
-
const user = await database.getUser(username);
|
|
263
|
-
return user && user.password === password;
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
user: {
|
|
267
|
-
getUserData: async (identifier) => database.getUser(identifier),
|
|
268
|
-
},
|
|
269
|
-
});
|
|
270
8
|
```
|
|
271
9
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
10
|
+
## Key Features
|
|
11
|
+
- **Supports multiple authentication strategies** (JWT, OAuth2, API Key, Basic, Local, Hybrid OAuth2).
|
|
12
|
+
- **Works with both HTTP and WebSocket protocols.**
|
|
13
|
+
- **Manages sessions, MFA, roles, account locks, and rate limiting.**
|
|
14
|
+
- **Easy configuration and extendability.**
|
|
15
|
+
- **Integration with frameworks like Express, NestJS, etc.**
|
|
277
16
|
|
|
278
|
-
|
|
279
|
-
Local authentication allows custom username/password authentication.
|
|
17
|
+
---
|
|
280
18
|
|
|
281
|
-
|
|
282
|
-
|
|
19
|
+
## Basic Usage
|
|
20
|
+
```typescript
|
|
21
|
+
import { SoapAuth, JwtStrategy } from "@soapjs/soap-auth";
|
|
283
22
|
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
extractCredentials: (context) => ({
|
|
287
|
-
identifier: context.body.username,
|
|
288
|
-
password: context.body.password,
|
|
289
|
-
}),
|
|
290
|
-
verifyCredentials: async (username, password) => {
|
|
291
|
-
const user = await database.getUser(username);
|
|
292
|
-
return user && user.password === password;
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
user: {
|
|
296
|
-
getUserData: async (identifier) => database.getUser(identifier),
|
|
297
|
-
},
|
|
298
|
-
});
|
|
299
|
-
```
|
|
23
|
+
const auth = new SoapAuth();
|
|
24
|
+
auth.addStrategy(new JwtStrategy({ secret: "super-secret-key" }), "jwt", "http");
|
|
300
25
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const authResult = await localAuth.authenticate(request);
|
|
304
|
-
console.log(authResult.user);
|
|
26
|
+
const result = await auth.authenticate("http", "jwt", request);
|
|
27
|
+
console.log(result.user);
|
|
305
28
|
```
|
|
306
29
|
|
|
307
|
-
|
|
308
|
-
API Key authentication extracts and verifies API keys sent in headers.
|
|
309
|
-
|
|
310
|
-
```ts
|
|
311
|
-
import { ApiKeyStrategy } from "@soapjs/soap-auth/strategies/api-key.strategy";
|
|
312
|
-
|
|
313
|
-
const apiKeyAuth = new ApiKeyStrategy({
|
|
314
|
-
extractApiKey: (context) => context.headers["x-api-key"],
|
|
315
|
-
retrieveUserByApiKey: async (apiKey) => database.getUserByApiKey(apiKey),
|
|
316
|
-
authorize: async (user, action) => user.permissions.includes(action),
|
|
317
|
-
isApiKeyExpired: async (apiKey) => false,
|
|
318
|
-
});
|
|
319
|
-
```
|
|
30
|
+
---
|
|
320
31
|
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
const authResult = await apiKeyAuth.authenticate(request);
|
|
324
|
-
console.log(authResult.user);
|
|
325
|
-
```
|
|
32
|
+
## Supported Authentication Strategies
|
|
326
33
|
|
|
327
|
-
|
|
328
|
-
JWT authentication verifies JSON Web Tokens (JWTs) passed in headers.
|
|
34
|
+
SoapAuth supports multiple authentication strategies. Below is a description and example configuration for each.
|
|
329
35
|
|
|
330
|
-
|
|
331
|
-
|
|
36
|
+
### **JWT Strategy** *(Token-based authentication)*
|
|
37
|
+
```typescript
|
|
38
|
+
import { JwtStrategy } from "@soapjs/soap-auth";
|
|
332
39
|
|
|
333
|
-
|
|
40
|
+
auth.addStrategy(new JwtStrategy({
|
|
41
|
+
secret: "your-secret-key",
|
|
334
42
|
accessToken: {
|
|
335
|
-
|
|
336
|
-
secretKey: "your-secret-key",
|
|
337
|
-
options: { expiresIn: "1h" },
|
|
338
|
-
},
|
|
339
|
-
retrieve: (context) => context.headers.authorization?.split(" ")[1],
|
|
43
|
+
expiresIn: "1h",
|
|
340
44
|
},
|
|
341
|
-
|
|
342
|
-
|
|
45
|
+
refreshToken: {
|
|
46
|
+
expiresIn: "7d",
|
|
343
47
|
},
|
|
344
|
-
});
|
|
48
|
+
}), "jwt", "http");
|
|
345
49
|
```
|
|
346
50
|
|
|
347
|
-
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
console.log(authResult.user);
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### **OAuth2 Authentication**
|
|
354
|
-
OAuth2 authentication enables integration with third-party providers.
|
|
355
|
-
|
|
356
|
-
```ts
|
|
357
|
-
import { OAuth2Strategy } from "@soapjs/soap-auth/strategies/oauth2.strategy";
|
|
51
|
+
### **OAuth2 Strategy** *(OAuth 2.0 authentication)*
|
|
52
|
+
```typescript
|
|
53
|
+
import { OAuth2Strategy } from "@soapjs/soap-auth";
|
|
358
54
|
|
|
359
|
-
|
|
55
|
+
auth.addStrategy(new OAuth2Strategy({
|
|
360
56
|
clientId: "your-client-id",
|
|
361
57
|
clientSecret: "your-client-secret",
|
|
362
58
|
redirectUri: "https://your-app.com/callback",
|
|
363
|
-
grantType: "authorization_code",
|
|
364
59
|
endpoints: {
|
|
365
|
-
authorizationUrl: "https://
|
|
366
|
-
tokenUrl: "https://
|
|
367
|
-
userInfoUrl: "https://provider.com/userinfo",
|
|
368
|
-
},
|
|
369
|
-
user: {
|
|
370
|
-
validateUser: async (userData) => database.getUser(userData.email),
|
|
60
|
+
authorizationUrl: "https://auth.server.com/auth",
|
|
61
|
+
tokenUrl: "https://auth.server.com/token",
|
|
371
62
|
},
|
|
372
|
-
});
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
#### **Authenticating a Request**
|
|
376
|
-
```ts
|
|
377
|
-
const authResult = await oauth2Auth.authenticate(request);
|
|
378
|
-
console.log(authResult.user);
|
|
63
|
+
}), "oauth2", "http");
|
|
379
64
|
```
|
|
380
65
|
|
|
381
|
-
### **
|
|
382
|
-
If you need a custom authentication method, you can extend `AuthStrategy`.
|
|
383
|
-
|
|
384
|
-
```ts
|
|
385
|
-
import { AuthStrategy } from "@soapjs/soap-auth";
|
|
386
|
-
|
|
387
|
-
class CustomAuthStrategy extends AuthStrategy {
|
|
388
|
-
async authenticate(context) {
|
|
389
|
-
const user = await database.findUser(context.credentials);
|
|
390
|
-
return user ? { user } : null;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### **Using other auth libraries with `soap-auth`**
|
|
396
|
-
Instead of implementing authentication manually, you can integrate `passport.js`.
|
|
397
|
-
|
|
398
|
-
```ts
|
|
399
|
-
import passport from "passport";
|
|
400
|
-
import { Strategy as FacebookStrategy } from "passport-facebook";
|
|
401
|
-
import { AuthStrategy } from "@soapjs/soap-auth";
|
|
402
|
-
|
|
403
|
-
class PassportAuthStrategy extends AuthStrategy {
|
|
404
|
-
|
|
405
|
-
init() {
|
|
406
|
-
passport.use(
|
|
407
|
-
new FacebookStrategy(
|
|
408
|
-
{
|
|
409
|
-
clientID: "your-facebook-client-id",
|
|
410
|
-
clientSecret: "your-facebook-client-secret",
|
|
411
|
-
callbackURL: "/auth/facebook/callback",
|
|
412
|
-
profileFields: ["id", "emails", "displayName"],
|
|
413
|
-
},
|
|
414
|
-
async (accessToken, refreshToken, profile, done) => {
|
|
415
|
-
const user = await database.findOrCreateUser(profile);
|
|
416
|
-
return done(null, user);
|
|
417
|
-
}
|
|
418
|
-
)
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
async authenticate(context) {
|
|
422
|
-
return new Promise((resolve, reject) => {
|
|
423
|
-
passport.authenticate("facebook", (error, user) => {
|
|
424
|
-
if (error || !user) return reject(new Error("Authentication failed"));
|
|
425
|
-
resolve({ user });
|
|
426
|
-
})(context.request, context.response);
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
---
|
|
456
|
-
|
|
457
|
-
## Installation
|
|
458
|
-
|
|
459
|
-
```sh
|
|
460
|
-
npm install @soapjs/soap-auth
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
---
|
|
464
|
-
|
|
465
|
-
## Features
|
|
466
|
-
|
|
467
|
-
- Multiple authentication strategies (local, OAuth2, JWT, API key, basic auth)
|
|
468
|
-
- Custom authentication strategy support
|
|
469
|
-
- Built-in session management with pluggable session stores
|
|
470
|
-
- Token handling for JWT authentication
|
|
471
|
-
- Extensible architecture with abstract base classes
|
|
472
|
-
- Compatible with framework adapters for seamless integration
|
|
473
|
-
|
|
474
|
-
---
|
|
475
|
-
|
|
476
|
-
## Core Classes Overview
|
|
477
|
-
|
|
478
|
-
### 1. `SoapAuth`
|
|
479
|
-
This is the main entry point for managing authentication. It initializes different strategies based on the provided configuration and provides methods for authentication, authorization, and session management.
|
|
480
|
-
|
|
481
|
-
### 2. `AuthStrategy`
|
|
482
|
-
The base interface that all strategies must implement. Provides methods such as `authenticate`, `authorize`, `init`, and `logout`.
|
|
483
|
-
|
|
484
|
-
### 3. `SessionHandler`
|
|
485
|
-
Handles session operations like retrieving, storing, and generating session IDs. It supports multiple session storage mechanisms such as in-memory and file-based stores.
|
|
486
|
-
|
|
487
|
-
### 4. `TokenAuthStrategy`
|
|
488
|
-
Abstract class for token-based authentication strategies, providing methods for handling access and refresh tokens.
|
|
489
|
-
|
|
490
|
-
### 5. `OAuth2Strategy`
|
|
491
|
-
Abstract class for token-based authentication strategies, providing methods for handling access and refresh tokens.
|
|
492
|
-
|
|
493
|
-
### 6. `CredentialAuthStrategy`
|
|
494
|
-
Abstract class for username-password-based authentication strategies.
|
|
495
|
-
|
|
496
|
-
### 7. `HttpAuthStrategyFactory` & `SocketAuthStrategyFactory`
|
|
497
|
-
Factories responsible for creating instances of HTTP and socket-based authentication strategies respectively.
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## Available Authentication Strategies
|
|
502
|
-
|
|
503
|
-
### 1. Local Strategy
|
|
504
|
-
|
|
505
|
-
**When to use:**
|
|
506
|
-
- Ideal for applications that require username and password authentication stored locally.
|
|
507
|
-
|
|
508
|
-
**Configuration example:**
|
|
66
|
+
### **API Key Strategy** *(Key-based authentication)*
|
|
509
67
|
```typescript
|
|
510
|
-
|
|
511
|
-
http: {
|
|
512
|
-
local: {
|
|
513
|
-
usernameField: "email",
|
|
514
|
-
passwordField: "password",
|
|
515
|
-
validateUser: async (username, password) => {
|
|
516
|
-
return username === "user@example.com" && password === "securepass" ? { id: 1, name: "John Doe" } : null;
|
|
517
|
-
},
|
|
518
|
-
},
|
|
519
|
-
},
|
|
520
|
-
};
|
|
521
|
-
```
|
|
68
|
+
import { ApiKeyStrategy } from "@soapjs/soap-auth";
|
|
522
69
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
**Configuration example:**
|
|
529
|
-
```typescript
|
|
530
|
-
const authConfig = {
|
|
531
|
-
http: {
|
|
532
|
-
oauth2: {
|
|
533
|
-
google: {
|
|
534
|
-
clientId: "your-client-id",
|
|
535
|
-
clientSecret: "your-client-secret",
|
|
536
|
-
redirectUri: "https://yourapp.com/auth/callback",
|
|
537
|
-
scope: "openid profile email",
|
|
538
|
-
endpoints: {
|
|
539
|
-
authorizationUrl: "https://accounts.google.com/o/oauth2/auth",
|
|
540
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
541
|
-
},
|
|
542
|
-
},
|
|
543
|
-
},
|
|
70
|
+
auth.addStrategy(new ApiKeyStrategy({
|
|
71
|
+
extractApiKey: (ctx) => ctx.headers["x-api-key"],
|
|
72
|
+
retrieveUserByApiKey: async (key) => {
|
|
73
|
+
return mockDatabase.findUserByApiKey(key);
|
|
544
74
|
},
|
|
545
|
-
};
|
|
75
|
+
}), "apikey", "http");
|
|
546
76
|
```
|
|
547
77
|
|
|
548
|
-
###
|
|
549
|
-
|
|
550
|
-
**When to use:**
|
|
551
|
-
- Suitable for stateless authentication where tokens are passed between the client and server.
|
|
552
|
-
|
|
553
|
-
**Configuration example:**
|
|
78
|
+
### **Basic Auth Strategy** *(Username & Password authentication)*
|
|
554
79
|
```typescript
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
},
|
|
80
|
+
import { BasicStrategy } from "@soapjs/soap-auth";
|
|
81
|
+
|
|
82
|
+
auth.addStrategy(new BasicStrategy({
|
|
83
|
+
extractCredentials: (ctx) => {
|
|
84
|
+
return { identifier: ctx.body.username, password: ctx.body.password };
|
|
85
|
+
},
|
|
86
|
+
verifyCredentials: async (id, pass) => {
|
|
87
|
+
return mockDatabase.verifyUser(id, pass);
|
|
564
88
|
},
|
|
565
|
-
};
|
|
89
|
+
}), "basic", "http");
|
|
566
90
|
```
|
|
567
91
|
|
|
568
|
-
###
|
|
569
|
-
|
|
570
|
-
**When to use:**
|
|
571
|
-
- Best for authenticating external services using static API keys.
|
|
572
|
-
|
|
573
|
-
**Configuration example:**
|
|
92
|
+
### **Local Strategy** *(Custom authentication logic)*
|
|
574
93
|
```typescript
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
},
|
|
582
|
-
},
|
|
94
|
+
import { LocalStrategy } from "@soapjs/soap-auth";
|
|
95
|
+
|
|
96
|
+
auth.addStrategy(new LocalStrategy({
|
|
97
|
+
extractCredentials: (ctx) => ({ identifier: ctx.query.email, password: ctx.query.pass }),
|
|
98
|
+
verifyCredentials: async (id, pass) => {
|
|
99
|
+
return mockDatabase.verifyUser(id, pass);
|
|
583
100
|
},
|
|
584
|
-
};
|
|
101
|
+
}), "local", "http");
|
|
585
102
|
```
|
|
586
103
|
|
|
587
|
-
###
|
|
588
|
-
|
|
589
|
-
**When to use:**
|
|
590
|
-
- Useful for simple username-password authentication with minimal overhead.
|
|
591
|
-
|
|
592
|
-
**Configuration example:**
|
|
104
|
+
### **Hybrid OAuth2 Strategy** *(Combination of multiple authentication methods)*
|
|
593
105
|
```typescript
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
106
|
+
import { HybridOAuth2Strategy } from "@soapjs/soap-auth";
|
|
107
|
+
|
|
108
|
+
auth.addStrategy(new HybridOAuth2Strategy({
|
|
109
|
+
clientId: "your-client-id",
|
|
110
|
+
clientSecret: "your-client-secret",
|
|
111
|
+
oauth2: {
|
|
112
|
+
endpoints: {
|
|
113
|
+
authorizationUrl: "https://oauth.provider.com/auth",
|
|
114
|
+
tokenUrl: "https://oauth.provider.com/token",
|
|
600
115
|
},
|
|
601
116
|
},
|
|
602
|
-
};
|
|
117
|
+
}), "hybrid-oauth2", "http");
|
|
603
118
|
```
|
|
604
119
|
|
|
605
120
|
---
|
|
606
121
|
|
|
607
|
-
##
|
|
608
|
-
|
|
122
|
+
## Configuration & Extensions
|
|
123
|
+
### Role Management
|
|
609
124
|
```typescript
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const user = await auth.authenticate("local", { email: "user@example.com", password: "securepass" });
|
|
616
|
-
console.log("Authenticated user:", user);
|
|
125
|
+
role: {
|
|
126
|
+
authorizeByRoles: async (user, roles) => roles.includes(user.role),
|
|
127
|
+
roles: ["admin", "user"]
|
|
128
|
+
}
|
|
617
129
|
```
|
|
618
|
-
|
|
619
|
-
---
|
|
620
|
-
|
|
621
|
-
## Creating a Custom Authentication Strategy
|
|
622
|
-
|
|
623
|
-
To create a custom strategy, extend the appropriate base class depending on the authentication type:
|
|
624
|
-
|
|
625
|
-
1. **For token-based strategies:** Extend `TokenAuthStrategy`.
|
|
626
|
-
2. **For credential-based strategies:** Extend `CredentialAuthStrategy`.
|
|
627
|
-
3. **For generic implementations:** Extend `BaseAuthStrategy` directly.
|
|
628
|
-
|
|
629
|
-
**Example:**
|
|
130
|
+
### Multi-Factor Authentication (MFA)
|
|
630
131
|
```typescript
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (token === "valid-token") {
|
|
635
|
-
return { user: { id: 1, role: "admin" }, tokens: { accessToken: token } };
|
|
636
|
-
}
|
|
637
|
-
throw new Error("Invalid token");
|
|
638
|
-
}
|
|
132
|
+
mfa: {
|
|
133
|
+
isMfaRequired: (user) => user.requiresMfa,
|
|
134
|
+
validateMfaCode: async (user, code) => mockDatabase.checkMfaCode(user, code),
|
|
639
135
|
}
|
|
640
136
|
```
|
|
641
|
-
|
|
642
|
-
---
|
|
643
|
-
|
|
644
|
-
## Session Management
|
|
645
|
-
|
|
646
|
-
SoapAuth supports session management through the `SessionHandler` class. The session can be stored using memory, files, or external databases via adapters.
|
|
647
|
-
|
|
648
|
-
**Example Session Configuration:**
|
|
137
|
+
### Account Locking after Failed Logins
|
|
649
138
|
```typescript
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
139
|
+
lock: {
|
|
140
|
+
isAccountLocked: async (account) => mockDatabase.isLocked(account),
|
|
141
|
+
lockAccount: async (account) => mockDatabase.lock(account),
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
### Rate Limiting
|
|
145
|
+
```typescript
|
|
146
|
+
rateLimit: {
|
|
147
|
+
checkRateLimit: async (ctx) => false, // No limits
|
|
148
|
+
}
|
|
657
149
|
```
|
|
658
150
|
|
|
659
151
|
---
|
|
660
152
|
|
|
661
|
-
##
|
|
153
|
+
## FAQ
|
|
154
|
+
**How to report an issue?**
|
|
155
|
+
Open an issue on GitHub.
|
|
662
156
|
|
|
663
|
-
|
|
157
|
+
**How to extend `soap-auth` with custom strategies?**
|
|
158
|
+
You can create your own class extending `BaseAuthStrategy` and implementing `authenticate()`.
|
|
664
159
|
|
|
665
|
-
|
|
666
|
-
// basic example
|
|
667
|
-
app.use(async (req, res, next) => {
|
|
668
|
-
try {
|
|
669
|
-
const user = await auth.authenticate("jwt", req);
|
|
670
|
-
req.user = user;
|
|
671
|
-
next();
|
|
672
|
-
} catch (error) {
|
|
673
|
-
res.status(401).send("Unauthorized");
|
|
674
|
-
}
|
|
675
|
-
});
|
|
676
|
-
```
|
|
160
|
+
---
|
|
677
161
|
## Issues
|
|
678
162
|
If you encounter any issues, please feel free to report them [here](https://github.com/soapjs/soap/issues/new/choose).
|
|
679
163
|
|
|
@@ -687,4 +171,4 @@ For any questions, collaboration interests, or support needs, you can contact us
|
|
|
687
171
|
- Warpcast: [@k4mr4ad](https://warpcast.com/k4mr4ad)
|
|
688
172
|
- Twitter: [@radoslawkamysz](https://x.com/radoslawkamysz)
|
|
689
173
|
## License
|
|
690
|
-
|
|
174
|
+
SoapAuth is licensed under the MIT License.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soapjs/soap-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://docs.soapjs.com",
|
|
6
6
|
"repository": "https://github.com/soapjs/soap-auth",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"axios": "^1.7.9",
|
|
29
29
|
"bcrypt": "^5.1.1",
|
|
30
30
|
"jsonwebtoken": "^9.0.2",
|
|
31
|
+
"jwks-rsa": "^3.1.0",
|
|
31
32
|
"uuid": "^9.0.1"
|
|
32
33
|
}
|
|
33
34
|
}
|