Skip to content

Commit 4c9f0dc

Browse files
committed
feat: complete OAuth integration with comprehensive unit tests
✅ **Features Added:** - **AUTH_MODE support**: none|resource_server|full modes - **OAuthTokenValidator**: Renamed from GatewayTokenValidator for clarity - **OAuth Provider integration**: Full OAuth server support for 'full' mode - **Comprehensive unit tests**: Config validation and token validator testing ✅ **Components:** - **Config validation**: Proper AUTH_MODE validation with detailed error messages - **Token validation**: JWT + introspection with proper error handling - **OAuth Provider**: Authorization flows for full OAuth server mode - **Unit tests**: 46 tests covering config and token validation scenarios ✅ **AUTH_MODE Behaviors:** - **none**: No authentication required - **resource_server**: Validates tokens from external OAuth provider - **full**: Acts as OAuth authorization server + validates tokens 🔒 **Security**: Proper JWT validation, audience checking, and error handling
1 parent 05f9765 commit 4c9f0dc

File tree

7 files changed

+856
-106
lines changed

7 files changed

+856
-106
lines changed

src/auth/index.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,48 @@
1-
import { ManagedOAuthServer } from "./oauth-server.ts";
2-
import { GatewayTokenValidator, BuiltinTokenValidator } from "./token-validator.ts";
1+
import { OAuthTokenValidator } from "./token-validator.ts";
2+
import { OAuthProvider } from "./oauth-provider.ts";
33
import { createAuthMiddleware } from "./middleware.ts";
44
import { getConfig } from "../config.ts";
55
import { logger } from "../logger.ts";
66

77
/**
8-
* Initialize authentication based on mode
8+
* Initialize authentication based on AUTH_MODE
99
*/
1010
export function initializeAuth() {
1111
const config = getConfig();
1212

13-
if (!config.ENABLE_AUTH) {
13+
if (config.AUTH_MODE === "none") {
1414
logger.info("Authentication is disabled");
15-
return { tokenValidator: null, oauthServer: null };
15+
return { tokenValidator: null, oauthProvider: null };
1616
}
1717

18-
if (config.AUTH_MODE === "gateway") {
19-
logger.info("Initializing gateway auth mode (resource server)");
20-
const tokenValidator = new GatewayTokenValidator(
21-
config.OAUTH_ISSUER!,
22-
config.OAUTH_AUDIENCE
23-
);
24-
return { tokenValidator, oauthServer: null };
18+
// Both resource_server and full modes need token validation
19+
const tokenValidator = new OAuthTokenValidator(
20+
config.OAUTH_ISSUER!,
21+
config.OAUTH_AUDIENCE
22+
);
23+
24+
if (config.AUTH_MODE === "resource_server") {
25+
logger.info("Initializing OAuth resource server mode");
26+
return { tokenValidator, oauthProvider: null };
2527
}
2628

27-
if (config.AUTH_MODE === "builtin") {
28-
logger.info("Initializing built-in auth mode (OAuth authorization server)");
29-
const oauthServer = new ManagedOAuthServer();
30-
const tokenValidator = new BuiltinTokenValidator(oauthServer);
31-
return { tokenValidator, oauthServer };
29+
if (config.AUTH_MODE === "full") {
30+
logger.info("Initializing OAuth full server mode with authorization endpoints");
31+
32+
// For full mode, also set up OAuth provider for authorization flows
33+
const oauthProvider = new OAuthProvider({
34+
clientId: config.OAUTH_CLIENT_ID!,
35+
clientSecret: config.OAUTH_CLIENT_SECRET!,
36+
authorizationEndpoint: `${config.BASE_URL || "http://localhost:3000"}/oauth/authorize`,
37+
tokenEndpoint: `${config.BASE_URL || "http://localhost:3000"}/oauth/token`,
38+
scope: "read write",
39+
redirectUri: "http://localhost:3000/oauth/callback", // This should be configurable
40+
});
41+
42+
return { tokenValidator, oauthProvider };
3243
}
3344

34-
throw new Error(`Unknown auth mode: ${config.AUTH_MODE}`);
45+
throw new Error(`Unknown AUTH_MODE: ${config.AUTH_MODE}`);
3546
}
3647

3748
/**
@@ -41,9 +52,8 @@ export function createAuthenticationMiddleware() {
4152
const { tokenValidator } = initializeAuth();
4253

4354
if (!tokenValidator) {
44-
// Return pass-through middleware when auth is disabled
4555
return (_req: any, _res: any, next: any) => next();
4656
}
4757

4858
return createAuthMiddleware(tokenValidator);
49-
}
59+
}

src/auth/middleware.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { Request, Response, NextFunction } from "express";
2-
import { GatewayTokenValidator, BuiltinTokenValidator } from "./token-validator.ts";
2+
import { OAuthTokenValidator, BuiltinTokenValidator } from "./token-validator.ts";
33
import { logger } from "../logger.ts";
44

55
export interface AuthenticatedRequest extends Request {
66
userId?: string;
77
accessToken?: string;
88
}
99

10-
type TokenValidator = GatewayTokenValidator | BuiltinTokenValidator;
10+
type TokenValidator = OAuthTokenValidator | BuiltinTokenValidator;
1111

1212
/**
1313
* Create authentication middleware that supports both gateway and built-in modes
@@ -27,7 +27,7 @@ export function createAuthMiddleware(tokenValidator: TokenValidator) {
2727
});
2828
}
2929

30-
const token = authHeader.substring(7); // Remove "Bearer " prefix
30+
const token = authHeader.substring(7);
3131

3232
try {
3333
const validation = await tokenValidator.validateToken(token);
@@ -39,7 +39,6 @@ export function createAuthMiddleware(tokenValidator: TokenValidator) {
3939
});
4040
}
4141

42-
// Add user context to request
4342
req.userId = validation.userId;
4443
req.accessToken = token;
4544

src/auth/oauth-provider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { randomBytes, createHash } from "node:crypto";
22
import { logger } from "../logger.ts";
3-
import { GatewayTokenValidator } from "./token-validator.ts";
3+
import { OAuthTokenValidator } from "./token-validator.ts";
44

55
export interface OAuthConfig {
66
clientId: string;
@@ -32,7 +32,7 @@ interface AuthorizationCodeData {
3232
*/
3333
export class OAuthProvider {
3434
#config: OAuthConfig;
35-
#tokenValidator: GatewayTokenValidator;
35+
#tokenValidator: OAuthTokenValidator;
3636

3737
// In-memory stores (use database in production)
3838
#authorizationCodes = new Map<string, AuthorizationCodeData>();
@@ -43,7 +43,7 @@ export class OAuthProvider {
4343

4444
// For built-in mode, we ARE the issuer
4545
const issuer = "http://localhost:3000"; // This should be dynamic based on server config
46-
this.#tokenValidator = new GatewayTokenValidator(issuer);
46+
this.#tokenValidator = new OAuthTokenValidator(issuer);
4747

4848
// Clean up expired codes and tokens periodically
4949
setInterval(() => this.cleanup(), 60 * 1000); // Every minute

0 commit comments

Comments
 (0)