Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 36x 36x 36x 36x 36x 32x 12x 20x 12x 12x 12x 8x 8x 2x 3x 2x 6x 6x 6x 36x 2x 1x 1x 36x 21x 36x 3x 36x 2x 1x 1x | /**
* OAuth Configuration for gitlab-mcp
*
* Handles OAuth mode detection and configuration validation.
* Uses Zod for runtime validation per CLAUDE.md standards.
*/
import { z } from "zod";
import { logger } from "../logger";
/**
* Zod schema for OAuth configuration
* All OAuth-specific environment variables are validated here
*/
const OAuthConfigSchema = z.object({
/** Whether OAuth mode is enabled */
enabled: z.literal(true),
/** Secret for signing MCP JWT tokens (minimum 32 characters) */
sessionSecret: z.string().min(32, "OAUTH_SESSION_SECRET must be at least 32 characters"),
/** GitLab OAuth application client ID */
gitlabClientId: z.string().min(1, "GITLAB_OAUTH_CLIENT_ID is required"),
/** GitLab OAuth application client secret (optional, for confidential apps) */
gitlabClientSecret: z.string().optional(),
/** OAuth scopes to request from GitLab */
gitlabScopes: z.string().default("api,read_user"),
/** MCP access token TTL in seconds */
tokenTtl: z.number().positive().default(3600),
/** MCP refresh token TTL in seconds */
refreshTokenTtl: z.number().positive().default(604800),
/** Device flow polling interval in seconds */
devicePollInterval: z.number().positive().default(5),
/** Device flow timeout in seconds */
deviceTimeout: z.number().positive().default(300),
});
/**
* Inferred TypeScript type from Zod schema
*/
export type OAuthConfig = z.infer<typeof OAuthConfigSchema>;
/**
* Cached OAuth configuration (loaded once at startup)
*/
let cachedOAuthConfig: OAuthConfig | null | undefined = undefined;
/**
* Load and validate OAuth configuration from environment variables
*
* Returns null if OAuth is not enabled (OAUTH_ENABLED !== 'true')
* Throws an error if OAuth is enabled but configuration is invalid
*
* @returns OAuthConfig if OAuth mode is enabled, null otherwise
*/
export function loadOAuthConfig(): OAuthConfig | null {
// Return cached config if already loaded
if (cachedOAuthConfig !== undefined) {
return cachedOAuthConfig;
}
// Check if OAuth mode is enabled
if (process.env.OAUTH_ENABLED !== "true") {
cachedOAuthConfig = null;
logger.debug("OAuth mode disabled (OAUTH_ENABLED !== 'true')");
return null;
}
// Use safeParse per CLAUDE.md Zod standards
const result = OAuthConfigSchema.safeParse({
enabled: true as const,
sessionSecret: process.env.OAUTH_SESSION_SECRET,
gitlabClientId: process.env.GITLAB_OAUTH_CLIENT_ID,
gitlabClientSecret: process.env.GITLAB_OAUTH_CLIENT_SECRET,
gitlabScopes: process.env.GITLAB_OAUTH_SCOPES ?? "api,read_user",
tokenTtl: parseInt(process.env.OAUTH_TOKEN_TTL ?? "3600", 10),
refreshTokenTtl: parseInt(process.env.OAUTH_REFRESH_TOKEN_TTL ?? "604800", 10),
devicePollInterval: parseInt(process.env.OAUTH_DEVICE_POLL_INTERVAL ?? "5", 10),
deviceTimeout: parseInt(process.env.OAUTH_DEVICE_TIMEOUT ?? "300", 10),
});
if (!result.success) {
const errorMessages = result.error.issues
.map(e => `${e.path.join(".")}: ${e.message}`)
.join(", ");
throw new Error(`Invalid OAuth configuration: ${errorMessages}`);
}
cachedOAuthConfig = result.data;
logger.info("OAuth mode enabled with valid configuration");
return result.data;
}
/**
* Validate static token configuration (used when OAuth is disabled)
*
* Throws an error if GITLAB_TOKEN is not set
*/
export function validateStaticConfig(): void {
if (!process.env.GITLAB_TOKEN) {
throw new Error("GITLAB_TOKEN is required when OAUTH_ENABLED is not true");
}
logger.debug("Static token mode: GITLAB_TOKEN configured");
}
/**
* Check if the server is running in OAuth mode
*
* @returns true if OAuth mode is enabled
*/
export function isOAuthEnabled(): boolean {
return loadOAuthConfig() !== null;
}
/**
* Reset cached configuration (for testing purposes)
*/
export function resetOAuthConfigCache(): void {
cachedOAuthConfig = undefined;
}
/**
* Get the authentication mode description
*
* @returns Human-readable description of the current auth mode
*/
export function getAuthModeDescription(): string {
if (isOAuthEnabled()) {
return "OAuth mode (per-user authentication via GitLab Device Flow)";
}
return "Static token mode (shared GITLAB_TOKEN)";
}
|