0
# Authentication
1
2
Comprehensive authentication system supporting basic, Kerberos, bearer token, and custom authentication methods.
3
4
## Capabilities
5
6
### Authentication Token Creation
7
8
Factory functions for creating authentication tokens for different authentication schemes.
9
10
```typescript { .api }
11
declare const auth: {
12
/**
13
* Create basic authentication token
14
* @param username - Username for authentication
15
* @param password - Password for authentication
16
* @param realm - Optional authentication realm
17
* @returns AuthToken for basic authentication
18
*/
19
basic(username: string, password: string, realm?: string): AuthToken;
20
21
/**
22
* Create Kerberos authentication token
23
* @param base64EncodedTicket - Base64 encoded Kerberos ticket
24
* @returns AuthToken for Kerberos authentication
25
*/
26
kerberos(base64EncodedTicket: string): AuthToken;
27
28
/**
29
* Create bearer token authentication
30
* @param base64EncodedToken - Base64 encoded bearer token
31
* @returns AuthToken for bearer token authentication
32
*/
33
bearer(base64EncodedToken: string): AuthToken;
34
35
/**
36
* Create custom authentication token
37
* @param principal - Authentication principal (username)
38
* @param credentials - Authentication credentials (password/token)
39
* @param realm - Authentication realm
40
* @param scheme - Custom authentication scheme
41
* @param parameters - Additional authentication parameters
42
* @returns AuthToken for custom authentication
43
*/
44
custom(
45
principal: string,
46
credentials: string,
47
realm: string,
48
scheme: string,
49
parameters?: Parameters
50
): AuthToken;
51
};
52
```
53
54
**Usage Examples:**
55
56
```typescript
57
import { driver, auth } from "neo4j-driver";
58
59
// Basic authentication (most common)
60
const basicDriver = driver(
61
"neo4j://localhost:7687",
62
auth.basic("neo4j", "password")
63
);
64
65
// Basic authentication with realm
66
const realmDriver = driver(
67
"neo4j://localhost:7687",
68
auth.basic("username", "password", "my-realm")
69
);
70
71
// Kerberos authentication
72
const kerberosTicket = "YII..."; // Base64 encoded Kerberos ticket
73
const kerberosDriver = driver(
74
"neo4j://localhost:7687",
75
auth.kerberos(kerberosTicket)
76
);
77
78
// Bearer token authentication
79
const bearerToken = "eyJ..."; // Base64 encoded JWT or similar
80
const bearerDriver = driver(
81
"neo4j://localhost:7687",
82
auth.bearer(bearerToken)
83
);
84
85
// Custom authentication
86
const customDriver = driver(
87
"neo4j://localhost:7687",
88
auth.custom("principal", "credentials", "realm", "custom-scheme", {
89
applicationId: "myapp",
90
version: "1.0"
91
})
92
);
93
94
// No authentication (for testing)
95
const noAuthDriver = driver(
96
"neo4j://localhost:7687",
97
auth.basic("", "", "")
98
);
99
```
100
101
### Authentication Token Interface
102
103
Structure of authentication tokens used by the driver.
104
105
```typescript { .api }
106
interface AuthToken {
107
/** Authentication scheme (basic, kerberos, bearer, custom, etc.) */
108
scheme: string;
109
110
/** Authentication principal (username) */
111
principal: string;
112
113
/** Authentication credentials (password, token, etc.) */
114
credentials: string;
115
116
/** Optional authentication realm */
117
realm?: string;
118
119
/** Additional authentication parameters */
120
parameters?: Record<string, any>;
121
}
122
```
123
124
**Usage Examples:**
125
126
```typescript
127
// Manually creating auth tokens (usually not needed)
128
const manualAuthToken: AuthToken = {
129
scheme: "basic",
130
principal: "neo4j",
131
credentials: "password",
132
realm: "neo4j"
133
};
134
135
const manualDriver = driver("neo4j://localhost:7687", manualAuthToken);
136
137
// Inspecting auth tokens (for debugging)
138
const authToken = auth.basic("user", "pass");
139
console.log(`Scheme: ${authToken.scheme}`); // "basic"
140
console.log(`Principal: ${authToken.principal}`); // "user"
141
console.log(`Has realm: ${!!authToken.realm}`); // false
142
```
143
144
### Authentication Token Managers
145
146
Advanced authentication with token management and automatic refresh capabilities.
147
148
```typescript { .api }
149
interface AuthTokenManager {
150
/**
151
* Get authentication token (called by driver as needed)
152
* @returns Promise resolving to auth token with optional expiration
153
*/
154
getToken(): Promise<AuthTokenAndExpiration>;
155
156
/**
157
* Handle security exceptions (e.g., token expired)
158
* @param authToken - The token that caused the security exception
159
* @param securityException - The security exception that occurred
160
* @returns true if the token was handled and retry should occur
161
*/
162
handleSecurityException(
163
authToken: AuthToken,
164
securityException: any
165
): Promise<boolean>;
166
}
167
168
interface AuthTokenAndExpiration {
169
/** The authentication token */
170
authToken: AuthToken;
171
172
/** Optional expiration time in milliseconds since epoch */
173
expiration?: number;
174
}
175
176
interface AuthTokenManagers {
177
/** Create a static auth token manager (no refresh) */
178
static(config: { authToken: AuthToken }): AuthTokenManager;
179
180
/** Create a bearer auth token manager with refresh capability */
181
bearer(config: BearerAuthTokenManagerConfig): AuthTokenManager;
182
183
/** Create a basic auth token manager */
184
basic(config: BasicAuthTokenManagerConfig): AuthTokenManager;
185
}
186
187
declare const authTokenManagers: AuthTokenManagers;
188
```
189
190
**Usage Examples:**
191
192
```typescript
193
import { driver, authTokenManagers, auth } from "neo4j-driver";
194
195
// Static auth token manager (simple wrapper)
196
const staticManager = authTokenManagers.static({
197
authToken: auth.basic("neo4j", "password")
198
});
199
200
const staticDriver = driver("neo4j://localhost:7687", staticManager);
201
202
// Bearer token manager with refresh
203
const bearerManager = authTokenManagers.bearer({
204
tokenProvider: async () => {
205
// Fetch fresh token from your auth service
206
const response = await fetch("/api/auth/token", {
207
method: "POST",
208
headers: { "Content-Type": "application/json" },
209
body: JSON.stringify({ userId: "current-user" })
210
});
211
212
const data = await response.json();
213
return {
214
authToken: auth.bearer(data.token),
215
expiration: Date.now() + (data.expiresIn * 1000)
216
};
217
}
218
});
219
220
const bearerDriver = driver("neo4j://localhost:7687", bearerManager);
221
222
// Custom auth token manager
223
class CustomAuthTokenManager implements AuthTokenManager {
224
private currentToken?: AuthToken;
225
private expiration?: number;
226
227
async getToken(): Promise<AuthTokenAndExpiration> {
228
// Check if current token is still valid
229
if (this.currentToken && this.expiration && Date.now() < this.expiration) {
230
return {
231
authToken: this.currentToken,
232
expiration: this.expiration
233
};
234
}
235
236
// Refresh token
237
const newToken = await this.refreshToken();
238
this.currentToken = newToken.authToken;
239
this.expiration = newToken.expiration;
240
241
return newToken;
242
}
243
244
async handleSecurityException(authToken: AuthToken, exception: any): Promise<boolean> {
245
console.log("Security exception occurred:", exception.message);
246
247
// Clear cached token to force refresh on next getToken call
248
this.currentToken = undefined;
249
this.expiration = undefined;
250
251
// Return true to indicate the driver should retry with a new token
252
return true;
253
}
254
255
private async refreshToken(): Promise<AuthTokenAndExpiration> {
256
// Your token refresh logic here
257
const response = await fetch("/api/auth/refresh", { method: "POST" });
258
const data = await response.json();
259
260
return {
261
authToken: auth.bearer(data.accessToken),
262
expiration: Date.now() + (data.expiresIn * 1000)
263
};
264
}
265
}
266
267
const customManager = new CustomAuthTokenManager();
268
const customDriver = driver("neo4j://localhost:7687", customManager);
269
```
270
271
### Static Auth Token Manager
272
273
Utility for creating static auth token managers.
274
275
```typescript { .api }
276
/**
277
* Create a static auth token manager from an auth token
278
* @param config - Configuration containing the auth token
279
* @returns AuthTokenManager that always returns the same token
280
*/
281
function staticAuthTokenManager(config: { authToken: AuthToken }): AuthTokenManager;
282
```
283
284
**Usage Examples:**
285
286
```typescript
287
import { driver, auth, staticAuthTokenManager } from "neo4j-driver";
288
289
// Create static manager directly
290
const manager = staticAuthTokenManager({
291
authToken: auth.basic("neo4j", "password")
292
});
293
294
const driverWithManager = driver("neo4j://localhost:7687", manager);
295
296
// Equivalent to using auth token directly
297
const directDriver = driver(
298
"neo4j://localhost:7687",
299
auth.basic("neo4j", "password")
300
);
301
302
// Static manager is useful when you need to pass an AuthTokenManager interface
303
function createDriverWithManager(authManager: AuthTokenManager) {
304
return driver("neo4j://localhost:7687", authManager);
305
}
306
307
const driver1 = createDriverWithManager(
308
staticAuthTokenManager({ authToken: auth.basic("user1", "pass1") })
309
);
310
311
const driver2 = createDriverWithManager(
312
staticAuthTokenManager({ authToken: auth.bearer("token123") })
313
);
314
```
315
316
### Session-Level Authentication
317
318
Override authentication at the session level for impersonation or multi-tenant scenarios.
319
320
```typescript { .api }
321
interface SessionConfig {
322
/** Session-level authentication override */
323
auth?: AuthToken | AuthTokenManager;
324
325
/** User to impersonate for this session */
326
impersonatedUser?: string;
327
328
// ... other session config properties
329
}
330
```
331
332
**Usage Examples:**
333
334
```typescript
335
// Driver with default authentication
336
const mainDriver = driver(
337
"neo4j://localhost:7687",
338
auth.basic("admin", "admin-password")
339
);
340
341
// Session with different authentication
342
const userSession = mainDriver.session({
343
auth: auth.basic("regular-user", "user-password"),
344
database: "userdata"
345
});
346
347
// Session with impersonation (requires Neo4j Enterprise)
348
const impersonatedSession = mainDriver.session({
349
impersonatedUser: "john.doe@company.com",
350
database: "analytics"
351
});
352
353
// Session with token manager override
354
const tokenManager = authTokenManagers.bearer({
355
tokenProvider: async () => ({
356
authToken: auth.bearer(await getUserToken("session-user")),
357
expiration: Date.now() + 3600000 // 1 hour
358
})
359
});
360
361
const tokenSession = mainDriver.session({
362
auth: tokenManager,
363
database: "reporting"
364
});
365
366
try {
367
// Use sessions with different authentication contexts
368
const userResult = await userSession.run("MATCH (n:UserData) RETURN count(n) AS count");
369
const impersonatedResult = await impersonatedSession.run("MATCH (n:Analytics) RETURN count(n) AS count");
370
const tokenResult = await tokenSession.run("MATCH (n:Report) RETURN count(n) AS count");
371
372
console.log(`User data: ${userResult.records[0].get("count")}`);
373
console.log(`Analytics: ${impersonatedResult.records[0].get("count")}`);
374
console.log(`Reports: ${tokenResult.records[0].get("count")}`);
375
} finally {
376
await userSession.close();
377
await impersonatedSession.close();
378
await tokenSession.close();
379
}
380
```
381
382
### Authentication Best Practices
383
384
**Security Considerations:**
385
386
```typescript
387
// Good: Use environment variables for credentials
388
const driver = driver(
389
process.env.NEO4J_URI || "neo4j://localhost:7687",
390
auth.basic(
391
process.env.NEO4J_USERNAME || "neo4j",
392
process.env.NEO4J_PASSWORD || ""
393
)
394
);
395
396
// Good: Use token managers for rotating credentials
397
const refreshingManager = authTokenManagers.bearer({
398
tokenProvider: async () => {
399
const token = await getTokenFromSecureStorage();
400
return {
401
authToken: auth.bearer(token.value),
402
expiration: token.expiresAt
403
};
404
}
405
});
406
407
// Good: Handle authentication errors gracefully
408
try {
409
const session = driver.session();
410
const result = await session.run("RETURN 1");
411
await session.close();
412
} catch (error) {
413
if (error.code === "Neo.ClientError.Security.Unauthorized") {
414
console.error("Authentication failed - check credentials");
415
// Trigger credential refresh or user re-authentication
416
} else {
417
console.error("Other error:", error.message);
418
}
419
}
420
421
// Avoid: Hardcoding credentials in source code
422
const badDriver = driver(
423
"neo4j://localhost:7687",
424
auth.basic("neo4j", "hardcoded-password") // Don't do this!
425
);
426
427
// Avoid: Logging authentication tokens
428
const authToken = auth.basic("user", "password");
429
console.log(authToken); // This logs the password!
430
```
431
432
**Token Refresh Patterns:**
433
434
```typescript
435
// Proactive token refresh
436
class ProactiveTokenManager implements AuthTokenManager {
437
private token?: AuthTokenAndExpiration;
438
private refreshPromise?: Promise<AuthTokenAndExpiration>;
439
440
async getToken(): Promise<AuthTokenAndExpiration> {
441
// If token expires in less than 5 minutes, refresh it
442
const refreshThreshold = 5 * 60 * 1000; // 5 minutes
443
444
if (!this.token ||
445
(this.token.expiration && this.token.expiration - Date.now() < refreshThreshold)) {
446
447
// Ensure only one refresh happens at a time
448
if (!this.refreshPromise) {
449
this.refreshPromise = this.refreshToken();
450
}
451
452
this.token = await this.refreshPromise;
453
this.refreshPromise = undefined;
454
}
455
456
return this.token;
457
}
458
459
async handleSecurityException(): Promise<boolean> {
460
// Force immediate refresh on security exception
461
this.token = undefined;
462
this.refreshPromise = undefined;
463
return true;
464
}
465
466
private async refreshToken(): Promise<AuthTokenAndExpiration> {
467
// Your token refresh implementation
468
const response = await fetch("/api/token/refresh", { method: "POST" });
469
const data = await response.json();
470
471
return {
472
authToken: auth.bearer(data.token),
473
expiration: Date.now() + (data.expiresIn * 1000)
474
};
475
}
476
}
477
```