# Auth Broker Roadmap

**Status:** ✅ Completed  
**Priority:** High  
**Created:** 2025-01-27  
**Last Updated:** 2025-11-30

**Note:** This roadmap has been completed. The `@mcp-abap-adt/auth-broker` package is now published and integrated into `mcp-abap-adt` server. See [Client Configuration Guide](../../user-guide/CLIENT_CONFIGURATION.md#destination-based-authentication) for usage details.

## Goal

Create a new package `@mcp-abap-adt/auth-broker` that handles JWT authentication based on HTTP headers (`x-sap-auth-type: jwt` and `x-mcp-destination`). The package will manage token retrieval, validation, and automatic refresh using service keys when needed.

## Requirements

### Core Functionality

1. **Header-based Authentication Detection**
   - Detect `x-sap-auth-type: jwt` header
   - Extract destination name from `x-mcp-destination` header (e.g., "TRIAL")
   - Only process when both headers are present

2. **Environment File Lookup**
   - Search for `{destination}.env` file (e.g., `TRIAL.env`) in a configurable directory
   - Extract JWT token from the `.env` file
   - Use token for authentication if file is found

3. **Token Validation**
   - Test connection using the token from `.env` file
   - Detect expired tokens (401/403 errors that indicate auth failure, not permission issues)

4. **Service Key Fallback**
   - If `.env` file is not found OR token is expired:
     - Search for `{destination}.json` file (e.g., `TRIAL.json`) containing service key
     - Use `@mcp-abap-adt/connection` utilities to refresh/obtain new token
     - Save new token to `.env` file for future use

5. **Token Management**
   - Cache tokens per destination
   - Provide `getToken(destination)` method
   - Provide `refreshToken(destination)` method
   - Handle token storage and retrieval

## Architecture

### Package Structure

```
mcp-abap-adt-auth-broker/
├── src/
│   ├── AuthBroker.ts          # Main class with getToken/refreshToken methods
│   ├── envLoader.ts            # Load .env files by destination name
│   ├── serviceKeyLoader.ts     # Load service key JSON files
│   ├── tokenValidator.ts       # Validate token by testing connection
│   ├── tokenRefresher.ts       # Refresh token using service key
│   └── index.ts                # Package exports
├── package.json
├── tsconfig.json
└── README.md
```

### Dependencies

- `@mcp-abap-adt/connection` - For token refresh utilities (`refreshJwtToken`)
- `axios` - For connection testing
- `dotenv` - For parsing `.env` files
- `fs` / `path` - For file system operations

## Implementation Steps

### Phase 1: Repository Setup

1. **Create new repository**
   - [ ] Create directory `/home/okyslytsia/prj/mcp-abap-adt-auth-broker`
   - [ ] Initialize npm package with name `@mcp-abap-adt/auth-broker`
   - [ ] Set up TypeScript configuration
   - [ ] Create basic package structure

2. **Package Configuration**
   - [ ] Configure `package.json` with proper name, version, and dependencies
   - [ ] Set up TypeScript build configuration
   - [ ] Configure exports in `package.json` (main, types, files)
   - [ ] Add build scripts

### Phase 2: Core Components

3. **Environment File Loader**
   - [ ] Create `envLoader.ts` module
   - [ ] Implement `loadEnvFile(destination: string, basePath?: string): Promise<EnvConfig | null>`
   - [ ] Search for `{destination}.env` in configurable directory
   - [ ] Parse `.env` file and extract:
     - `SAP_JWT_TOKEN`
     - `SAP_REFRESH_TOKEN` (optional)
     - `SAP_URL`
     - `SAP_CLIENT` (optional)
     - `SAP_UAA_URL` (optional, for refresh)
     - `SAP_UAA_CLIENT_ID` (optional, for refresh)
     - `SAP_UAA_CLIENT_SECRET` (optional, for refresh)
   - [ ] Return structured config object or null if not found

4. **Service Key Loader**
   - [ ] Create `serviceKeyLoader.ts` module
   - [ ] Implement `loadServiceKey(destination: string, basePath?: string): Promise<ServiceKey | null>`
   - [ ] Search for `{destination}.json` file
   - [ ] Parse JSON and validate structure (must have `uaa` object with `url`, `clientid`, `clientsecret`)
   - [ ] Extract ABAP URL from service key (`url`, `abap.url`, or `sap_url`)
   - [ ] Return structured service key object or null if not found

5. **Token Validator**
   - [ ] Create `tokenValidator.ts` module
   - [ ] Implement `validateToken(token: string, sapUrl: string): Promise<boolean>`
   - [ ] Make test request to SAP system (e.g., `/sap/bc/adt/core/discovery`)
   - [ ] Handle 401/403 errors:
     - Distinguish between auth errors (token expired) and permission errors
     - Return `false` for expired tokens
     - Return `true` for valid tokens
   - [ ] Handle network errors appropriately

6. **Token Refresher**
   - [ ] Create `tokenRefresher.ts` module
   - [ ] Import `refreshJwtToken` from `@mcp-abap-adt/connection`
   - [ ] Implement `refreshTokenFromServiceKey(serviceKey: ServiceKey): Promise<TokenRefreshResult>`
   - [ ] Use service key to obtain initial token (if needed) or refresh existing token
   - [ ] Handle OAuth flow if refresh token is not available (may need to use browser flow or client credentials)
   - [ ] Return new access token and refresh token

### Phase 3: Main AuthBroker Class

7. **AuthBroker Class Implementation**
   - [ ] Create `AuthBroker.ts` class
   - [ ] Constructor accepts:
     - `basePath?: string` - Base directory for searching `.env` and `.json` files (default: current working directory or configurable)
   - [ ] Implement `getToken(destination: string): Promise<string>`
     - Check cache for existing valid token
     - Load `{destination}.env` file
     - Extract token from `.env`
     - Validate token by testing connection
     - If valid, cache and return token
     - If invalid or not found, call `refreshToken()`
   - [ ] Implement `refreshToken(destination: string): Promise<string>`
     - Load `{destination}.json` service key file
     - Use token refresher to obtain new token
     - Save new token to `{destination}.env` file
     - Cache new token
     - Return new token
   - [ ] Implement token caching (in-memory cache per destination)
   - [ ] Implement error handling and logging

8. **Token Storage**
   - [ ] Implement `saveTokenToEnv(destination: string, token: string, refreshToken?: string, config?: Partial<EnvConfig>): Promise<void>`
   - [ ] Update or create `{destination}.env` file
   - [ ] Preserve existing values that are not being updated
   - [ ] Write file atomically (write to temp file, then rename)

### Phase 4: NPM Publishing Setup

9. **Package.json Configuration**
   - [ ] Configure `package.json` for npm publishing:
     - [ ] Set `"name": "@mcp-abap-adt/auth-broker"`
     - [ ] Set initial version (e.g., `"0.1.0"`)
     - [ ] Add `"publishConfig": { "access": "public" }` for scoped package
     - [ ] Configure `"files"` array to include only necessary files:
       - `dist/` - compiled JavaScript and TypeScript definitions
       - `README.md` - package documentation
       - `LICENSE` - license file
     - [ ] Set `"main": "dist/index.js"` and `"types": "dist/index.d.ts"`
     - [ ] Add proper `"repository"` field with GitHub URL
     - [ ] Add `"keywords"` for npm searchability
     - [ ] Add `"homepage"` and `"bugs"` URLs
     - [ ] Configure `"engines"` (Node.js >= 18.0.0)
     - [ ] Add `"prepublishOnly"` script to build before publishing

10. **NPM Account Setup**
    - [ ] Verify npm account access to `@mcp-abap-adt` scope
    - [ ] If needed, create organization or request access to existing scope
    - [ ] Configure npm authentication:
      - [ ] Run `npm login` or configure `.npmrc` with auth token
      - [ ] Verify access: `npm whoami`
      - [ ] Test scope access: `npm access ls-packages @mcp-abap-adt`

11. **NPM Configuration Files**
    - [ ] Create `.npmrc` file (if needed) with:
      - [ ] `package-lock=true` - ensure lock file is generated
      - [ ] Other npm settings as needed (see existing packages for reference)
    - [ ] Add `.npmignore` file (if needed) to exclude:
      - [ ] `src/` - source files (only `dist/` should be published)
      - [ ] `node_modules/`
      - [ ] `*.test.ts`, `*.spec.ts` - test files
      - [ ] `tsconfig.json`, `jest.config.js` - build configs
      - [ ] `.git/`, `.github/` - version control files
      - [ ] Development files

12. **Build and Test Package Locally**
    - [ ] Run `npm run build` to ensure TypeScript compiles correctly
    - [ ] Run `npm pack` to create `.tgz` package locally
    - [ ] Verify package contents: `tar -tzf *.tgz | head -20`
    - [ ] Test package installation locally:
      ```bash
      npm pack
      npm install -g ./mcp-abap-adt-auth-broker-*.tgz
      ```
    - [ ] Verify package can be imported in test project
    - [ ] Clean up test installation

13. **GitHub Repository Setup** (if separate repo)
    - [ ] Create GitHub repository (if package is in separate repo)
    - [ ] Initialize git repository
    - [ ] Add `.gitignore` file
    - [ ] Create initial commit
    - [ ] Push to GitHub
    - [ ] Update `package.json` repository field with correct URL

14. **GitHub Actions for Publishing** (optional but recommended)
    - [ ] Create `.github/workflows/publish-npm.yml`:
      - [ ] Trigger on version tags (`v*.*.*`)
      - [ ] Setup Node.js
      - [ ] Install dependencies
      - [ ] Run tests
      - [ ] Build package
      - [ ] Publish to npm using `NPM_TOKEN` secret
    - [ ] Add `NPM_TOKEN` to GitHub repository secrets
    - [ ] Test workflow with dry-run or test publish

15. **First Publication**
    - [ ] Ensure all code is complete and tested
    - [ ] Update version in `package.json` (e.g., `0.1.0`)
    - [ ] Build package: `npm run build`
    - [ ] Verify package: `npm pack`
    - [ ] Publish to npm:
      ```bash
      npm publish --access public
      ```
    - [ ] Verify publication:
      - [ ] Check npm registry: `npm view @mcp-abap-adt/auth-broker`
      - [ ] Test installation: `npm install @mcp-abap-adt/auth-broker`
      - [ ] Verify package works in test project

16. **Version Management**
    - [ ] Document versioning strategy (semantic versioning)
    - [ ] Set up `CHANGELOG.md` for tracking changes
    - [ ] Document release process
    - [ ] Consider using `npm version` command for version bumps

### Phase 5: Integration with mcp-abap-adt

17. **Package Installation**
    - [ ] Add `@mcp-abap-adt/auth-broker` as dependency to `mcp-abap-adt/package.json`
    - [ ] Install package: `npm install @mcp-abap-adt/auth-broker`
    - [ ] Verify package is installed correctly

18. **Header Processing Integration**
    - [ ] Modify `applyAuthHeaders()` method in `mcp_abap_adt_server` class
    - [ ] Add detection for `x-mcp-destination` header
    - [ ] When `x-sap-auth-type: jwt` AND `x-mcp-destination` are present:
      - Create `AuthBroker` instance
      - Call `getToken(destination)` to obtain token
      - Use returned token instead of token from `x-sap-jwt-token` header
      - Update `processJwtConfigUpdate()` to use broker token

19. **Configuration**
    - [ ] Add configuration option for base path where `.env` and `.json` files are stored
    - [ ] Default to current working directory or a configurable directory (e.g., `~/.mcp-abap-adt/destinations/`)
    - [ ] Allow override via environment variable (e.g., `MCP_AUTH_BROKER_BASE_PATH`)

### Phase 6: Testing and Documentation

20. **Unit Tests**
    - [ ] Test `envLoader` with various `.env` file formats
    - [ ] Test `serviceKeyLoader` with valid and invalid service keys
    - [ ] Test `tokenValidator` with valid, expired, and invalid tokens
    - [ ] Test `tokenRefresher` with service keys
    - [ ] Test `AuthBroker.getToken()` flow
    - [ ] Test `AuthBroker.refreshToken()` flow
    - [ ] Test error handling scenarios

21. **Integration Tests**
    - [ ] Test full flow: header → destination → `.env` file → token validation → token refresh if needed
    - [ ] Test with real SAP system (if available)
    - [ ] Test token caching behavior
    - [ ] Test concurrent requests for same destination

22. **Documentation**
    - [ ] Write README.md for `auth-broker` package
    - [ ] Document API (AuthBroker class methods)
    - [ ] Document file structure requirements (`.env` and `.json` file formats)
    - [ ] Document configuration options
    - [ ] Add usage examples
    - [ ] Update `mcp-abap-adt` documentation to explain new header-based destination authentication

## File Structure Details

### Environment File Format (`{destination}.env`)

```env
SAP_URL=https://your-system.abap.us10.hana.ondemand.com
SAP_CLIENT=100
SAP_JWT_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
SAP_REFRESH_TOKEN=refresh_token_string
SAP_UAA_URL=https://your-account.authentication.us10.hana.ondemand.com
SAP_UAA_CLIENT_ID=client_id
SAP_UAA_CLIENT_SECRET=client_secret
```

### Service Key File Format (`{destination}.json`)

```json
{
  "url": "https://your-system.abap.us10.hana.ondemand.com",
  "uaa": {
    "url": "https://your-account.authentication.us10.hana.ondemand.com",
    "clientid": "your_client_id",
    "clientsecret": "your_client_secret"
  }
}
```

## API Design

### AuthBroker Class

```typescript
export class AuthBroker {
  constructor(basePath?: string);
  
  /**
   * Get authentication token for destination.
   * Tries to load from .env file, validates it, and refreshes if needed.
   */
  getToken(destination: string): Promise<string>;
  
  /**
   * Force refresh token for destination using service key.
   */
  refreshToken(destination: string): Promise<string>;
  
  /**
   * Clear cached token for destination.
   */
  clearCache(destination: string): void;
  
  /**
   * Clear all cached tokens.
   */
  clearAllCache(): void;
}
```

## Integration Points

### In mcp-abap-adt/src/index.ts

Modify `applyAuthHeaders()` method:

```typescript
// When x-sap-auth-type: jwt AND x-mcp-destination are present
if (isJwtAuth && destination) {
  const authBroker = new AuthBroker(configurableBasePath);
  const token = await authBroker.getToken(destination);
  // Use token instead of header token
  this.processJwtConfigUpdate(sapUrl, token, refreshToken, sessionId);
}
```

## Configuration

### Environment Variables

- `MCP_AUTH_BROKER_BASE_PATH` - Base directory for searching `.env` and `.json` files (default: current working directory)

### Default File Locations

1. Check `MCP_AUTH_BROKER_BASE_PATH` if set
2. Fallback to current working directory
3. Future: Support `~/.mcp-abap-adt/destinations/` as default

## Error Handling

- File not found: Log warning, attempt service key refresh
- Invalid token: Attempt refresh using service key
- Service key not found: Throw error with clear message
- Token refresh failure: Throw error with details
- Network errors: Retry with exponential backoff (if applicable)

## Future Enhancements

- Support for multiple base paths (search in multiple directories)
- Token expiration prediction (refresh before expiration)
- Support for encrypted service key files
- Integration with keychain/credential stores
- Support for destination-specific configuration files
- Metrics and monitoring hooks

## Dependencies

### Required
- `@mcp-abap-adt/connection` - For `refreshJwtToken` utility
- `axios` - For HTTP requests (token validation)
- `dotenv` - For parsing `.env` files

### Optional
- `fs-extra` - For better file operations (if needed)
- `winston` or similar - For structured logging (if needed)

## Notes

- The package should be lightweight and focused only on token management
- It should not handle actual ADT requests - that's the responsibility of `@mcp-abap-adt/connection`
- Token validation should be minimal (just test connection, don't do full ADT operations)
- The package should be stateless where possible, but token caching is acceptable for performance
- Consider thread-safety if multiple requests come in for the same destination simultaneously
