UNPKG

okta-mcp-server

Version:

Model Context Protocol (MCP) server for Okta API operations with support for bulk operations and caching

201 lines 6.71 kB
import { faker } from '@faker-js/faker'; export class AuthSimulator { config; tokens; constructor(config = { requireAuth: true, tokenExpiration: 3600, // 1 hour }) { this.config = config; this.tokens = config.validTokens || new Map(); // Generate some default valid tokens if (this.tokens.size === 0) { this.generateDefaultTokens(); } } generateDefaultTokens() { // API Token (SSWS) const apiToken = { token: '00QCjAl4MlV-WPXM0n-eiPGHlZ0y0WZgK-_8bCRjARmUAl11gkLlsEYamWLP', type: 'SSWS', expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000, // 1 year userId: 'system', }; this.tokens.set(apiToken.token, apiToken); // OAuth Bearer tokens const bearerTokens = [ { token: 'eyJraWQiOiJyTzhPTGJmMFlfWVpGTF9XaVlsM1BjX0dKQ0xnU25YbTlTbGFLQUx', type: 'Bearer', expiresAt: Date.now() + this.config.tokenExpiration * 1000, scopes: ['okta.users.read', 'okta.groups.read'], clientId: '0oab8eb55Kb9jdMIr5d6', }, { token: 'eyJraWQiOiJBZG1pblRva2VuXzEyMzQ1Njc4OTAiLCJhbGciOiJSUzI1NiJ9', type: 'Bearer', expiresAt: Date.now() + this.config.tokenExpiration * 1000, scopes: ['okta.users.manage', 'okta.groups.manage', 'okta.apps.manage'], clientId: '0oab8eb55Kb9jdMIr5d7', }, ]; bearerTokens.forEach((token) => { this.tokens.set(token.token, token); }); } validateAuth(authHeader) { if (!this.config.requireAuth) { return { valid: true }; } if (!authHeader) { return { valid: false, error: 'Authorization header required', }; } // Parse authorization header const parts = authHeader.split(' '); if (parts.length !== 2) { return { valid: false, error: 'Invalid authorization header format', }; } const [type, tokenValue] = parts; // Check token type if (type !== 'SSWS' && type !== 'Bearer') { return { valid: false, error: 'Invalid token type', }; } if (!tokenValue) { return { valid: false, error: 'Missing token value', }; } // Look up token const token = this.tokens.get(tokenValue); if (!token) { return { valid: false, error: 'Invalid token', }; } // Check token type matches if (token.type !== type) { return { valid: false, error: 'Token type mismatch', }; } // Check expiration if (token.expiresAt < Date.now()) { return { valid: false, error: 'Token expired', }; } return { valid: true, token, }; } validateScopes(token, requiredScopes) { if (!token.scopes) return true; // API tokens have all scopes return requiredScopes.every((scope) => token.scopes.includes(scope) || token.scopes.includes('*') // Wildcard scope ); } // Generate a new access token generateAccessToken(clientId, scopes, userId) { const token = { token: this.generateTokenString(), type: 'Bearer', expiresAt: Date.now() + this.config.tokenExpiration * 1000, scopes, clientId, }; if (userId) { token.userId = userId; } this.tokens.set(token.token, token); return token; } // Generate a new API token generateApiToken(userId) { const token = { token: this.generateApiTokenString(), type: 'SSWS', expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000, // 1 year userId, }; this.tokens.set(token.token, token); return token; } // Revoke a token revokeToken(tokenValue) { return this.tokens.delete(tokenValue); } // Refresh a token refreshToken(oldToken) { const existing = this.tokens.get(oldToken); if (!existing || existing.type !== 'Bearer') { return null; } // Create new token with same properties but new value and expiration const newToken = { ...existing, token: this.generateTokenString(), expiresAt: Date.now() + this.config.tokenExpiration * 1000, }; // Remove old token and add new one this.tokens.delete(oldToken); this.tokens.set(newToken.token, newToken); return newToken; } generateTokenString() { // Simulate JWT-like token const header = Buffer.from(JSON.stringify({ kid: faker.string.alphanumeric(20), alg: 'RS256', })).toString('base64url'); const payload = Buffer.from(JSON.stringify({ iss: 'https://dev-12345.okta.com', iat: Math.floor(Date.now() / 1000), exp: Math.floor((Date.now() + this.config.tokenExpiration * 1000) / 1000), jti: faker.string.uuid(), })).toString('base64url'); const signature = faker.string.alphanumeric(86); return `${header}.${payload}.${signature}`; } generateApiTokenString() { // Simulate Okta API token format return `00${faker.string.alphanumeric(40)}_${faker.string.alphanumeric(8)}`; } // Get token info (for introspection endpoint) introspectToken(tokenValue) { const token = this.tokens.get(tokenValue); if (!token) { return { active: false, }; } const active = token.expiresAt > Date.now(); return { active, scope: token.scopes?.join(' '), client_id: token.clientId, username: token.userId, exp: Math.floor(token.expiresAt / 1000), iat: Math.floor((token.expiresAt - this.config.tokenExpiration * 1000) / 1000), sub: token.userId, aud: 'api://default', iss: 'https://dev-12345.okta.com/oauth2/default', jti: faker.string.uuid(), token_type: token.type, }; } } //# sourceMappingURL=auth-simulator.js.map