@mcp-abap-adt/auth-stores
v1.0.4
Published
Stores for MCP ABAP ADT auth-broker - BTP, ABAP, and XSUAA implementations
Maintainers
Readme
@mcp-abap-adt/auth-stores
Stores for MCP ABAP ADT auth-broker - BTP, ABAP, and XSUAA implementations.
This package provides file-based and in-memory stores for service keys and sessions used by the @mcp-abap-adt/auth-broker package.
Installation
npm install @mcp-abap-adt/auth-storesOverview
This package implements the IServiceKeyStore and ISessionStore interfaces from @mcp-abap-adt/interfaces:
- Service Key Stores: Read service key JSON files from a specified directory
- Session Stores: Read/write session data from/to
.envfiles or in-memory storage - File Handlers: Utility classes for working with JSON and ENV files
Responsibilities and Design Principles
Core Development Principle
Interface-Only Communication: This package follows a fundamental development principle: all interactions with external dependencies happen ONLY through interfaces. The code knows NOTHING beyond what is defined in the interfaces.
This means:
- Does not know about concrete implementation classes from other packages
- Does not know about internal data structures or methods not defined in interfaces
- Does not make assumptions about implementation behavior beyond interface contracts
- Does not access properties or methods not explicitly defined in interfaces
This principle ensures:
- Loose coupling: Stores are decoupled from concrete implementations in other packages
- Flexibility: New implementations can be added without modifying stores
- Testability: Easy to mock dependencies for testing
- Maintainability: Changes to implementations don't affect stores
Package Responsibilities
This package is responsible for:
- Implementing storage interfaces: Provides concrete implementations of
IServiceKeyStoreandISessionStoreinterfaces defined in@mcp-abap-adt/interfaces - File I/O operations: Handles reading and writing service key JSON files and session
.envfiles - Data format conversion: Converts between interface types (
IConfig,IConnectionConfig,IAuthorizationConfig) and internal storage formats - Platform-specific handling: Provides different store implementations for ABAP, BTP, and XSUAA with their specific data formats
What This Package Does
- Implements interfaces: Provides concrete implementations of
IServiceKeyStoreandISessionStore - Handles file operations: Reads/writes JSON and
.envfiles using atomic operations - Manages data formats: Converts between interface types and internal storage formats (e.g.,
AbapSessionData,BtpBaseSessionData) - Provides utilities: File handlers (
JsonFileHandler,EnvFileHandler) for safe file operations
What This Package Does NOT Do
- Does NOT implement authentication logic: Token acquisition and OAuth2 flows are handled by
@mcp-abap-adt/auth-providers - Does NOT orchestrate authentication: Token lifecycle management is handled by
@mcp-abap-adt/auth-broker - Does NOT know about token validation: Token validation logic is not part of this package
- Does NOT interact with external services: All HTTP requests and OAuth flows are handled by other packages
External Dependencies
This package interacts with external packages ONLY through interfaces:
@mcp-abap-adt/interfaces: Uses interfaces (IServiceKeyStore,ISessionStore,IConfig,IConnectionConfig,IAuthorizationConfig,ILogger) - does not know about concrete implementations in other packages- No direct dependencies on other packages: All interactions happen through well-defined interfaces
Store Types
Service Key Stores
Service key stores read JSON files containing UAA credentials and connection information:
BtpServiceKeyStore- Reads XSUAA service keys for base BTP (direct XSUAA format)AbapServiceKeyStore- Reads ABAP service keys (with nesteduaaobject)XsuaaServiceKeyStore- Reads XSUAA service keys (alias for BtpServiceKeyStore)
Session Stores
Session stores manage authentication tokens and configuration:
File-based stores (persist to .env files):
BtpSessionStore- Stores base BTP sessions usingXSUAA_*environment variablesAbapSessionStore- Stores ABAP sessions usingSAP_*environment variablesXsuaaSessionStore- Stores XSUAA sessions usingXSUAA_*environment variables
In-memory stores (non-persistent, secure):
SafeBtpSessionStore- In-memory store for base BTP sessionsSafeAbapSessionStore- In-memory store for ABAP sessionsSafeXsuaaSessionStore- In-memory store for XSUAA sessions
File-based single-file stores:
EnvFileSessionStore- Reads from a specific.envfile path (e.g.,--env /path/to/.env)
Usage
BTP Stores (base BTP without sapUrl)
import { BtpServiceKeyStore, BtpSessionStore, SafeBtpSessionStore } from '@mcp-abap-adt/auth-stores';
// Service key store - reads {destination}.json files from directory
const serviceKeyStore = new BtpServiceKeyStore('/path/to/service-keys');
// File-based session store - reads/writes {destination}.env files
// defaultServiceUrl is REQUIRED (cannot be obtained from service key)
const sessionStore = new BtpSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
// In-memory session store (non-persistent)
// defaultServiceUrl is REQUIRED (cannot be obtained from service key)
const safeSessionStore = new SafeBtpSessionStore('https://default.mcp.com', logger);ABAP Stores (with sapUrl)
import {
AbapServiceKeyStore,
AbapSessionStore,
SafeAbapSessionStore,
SamlSessionStore,
SafeSamlSessionStore,
} from '@mcp-abap-adt/auth-stores';
// Service key store - reads ABAP service keys with nested uaa object
const serviceKeyStore = new AbapServiceKeyStore('/path/to/service-keys');
// File-based session store - stores ABAP sessions with SAP_* env vars
const sessionStore = new AbapSessionStore('/path/to/sessions');
// In-memory session store
const safeSessionStore = new SafeAbapSessionStore();
// SAML aliases (same behavior as ABAP stores)
const samlSessionStore = new SamlSessionStore('/path/to/sessions');
const safeSamlSessionStore = new SafeSamlSessionStore();XSUAA Stores
import { XsuaaServiceKeyStore, XsuaaSessionStore, SafeXsuaaSessionStore } from '@mcp-abap-adt/auth-stores';
// Service key store - reads XSUAA service keys
const serviceKeyStore = new XsuaaServiceKeyStore('/path/to/service-keys');
// File-based session store - stores XSUAA sessions
// defaultServiceUrl is REQUIRED (cannot be obtained from service key)
const sessionStore = new XsuaaSessionStore('/path/to/sessions', 'https://default.mcp.com', logger);
// In-memory session store
// defaultServiceUrl is REQUIRED (cannot be obtained from service key)
const safeSessionStore = new SafeXsuaaSessionStore('https://default.mcp.com', logger);EnvFileSessionStore (Single File)
EnvFileSessionStore reads connection configuration from a specific .env file path rather than a directory. This is useful for the --env CLI option.
import { EnvFileSessionStore } from '@mcp-abap-adt/auth-stores';
// Create store pointing to specific .env file
const store = new EnvFileSessionStore('/path/to/.env', logger);
// Check the auth type from the file
const authType = store.getAuthType(); // 'basic' | 'jwt' | 'saml' | null
// Load session (works like other session stores)
const config = await store.loadSession('default');
console.log(config?.serviceUrl, config?.authType);
// For basic auth
console.log(config?.username, config?.password);
// For JWT auth
console.log(config?.authorizationToken, config?.refreshToken);Env file format:
# Connection
SAP_URL=https://your-sap-system.com
SAP_CLIENT=100
# Auth type: 'basic', 'jwt', or 'saml' (defaults to 'basic')
SAP_AUTH_TYPE=basic
# Basic auth credentials
SAP_USERNAME=your-username
SAP_PASSWORD=your-password
# OR JWT auth
# SAP_AUTH_TYPE=jwt
# SAP_JWT_TOKEN=your-jwt-token
# SAP_REFRESH_TOKEN=your-refresh-token
# SAP_UAA_URL=https://uaa.example.com
# SAP_UAA_CLIENT_ID=client-id
# SAP_UAA_CLIENT_SECRET=client-secret
# OR SAML auth (session cookies, base64-encoded)
# SAP_AUTH_TYPE=saml
# SAP_SESSION_COOKIES_B64=base64-encoded-cookie-stringImportant: This store is read-only for the file. Token updates (e.g., refreshed JWT tokens) are stored in memory only and do not modify the original .env file.
Directory Configuration
All stores accept a single directory path in the constructor:
// Single directory path
const store = new BtpServiceKeyStore('/path/to/service-keys');
// File-based session stores automatically create directory in constructor if it doesn't exist
const sessionStore = new AbapSessionStore('/path/to/sessions'); // Directory created automaticallyNote: File-based session stores (AbapSessionStore, BtpSessionStore, XsuaaSessionStore) automatically create the directory in the constructor if it doesn't exist. Stores are ready to use immediately after construction.
Default Service URL Configuration
For XSUAA and BTP stores: defaultServiceUrl is required in the constructor because serviceUrl cannot be obtained from service keys:
XsuaaSessionStore(directory, defaultServiceUrl, log?)-defaultServiceUrlis requiredSafeXsuaaSessionStore(defaultServiceUrl, log?)-defaultServiceUrlis requiredBtpSessionStore(directory, defaultServiceUrl, log?)-defaultServiceUrlis requiredSafeBtpSessionStore(defaultServiceUrl, log?)-defaultServiceUrlis required
For ABAP stores: defaultServiceUrl is optional because serviceUrl can be obtained from ABAP service keys:
AbapSessionStore(directory, log?, defaultServiceUrl?)-defaultServiceUrlis optionalSafeAbapSessionStore(log?, defaultServiceUrl?)-defaultServiceUrlis optional
The defaultServiceUrl is used when creating new sessions via setConnectionConfig or setAuthorizationConfig if config.serviceUrl is not provided. It is never used to modify existing sessions.
Service Key Format
ABAP Service Key (with nested uaa object):
{
"uaa": {
"url": "https://...authentication...hana.ondemand.com",
"clientid": "...",
"clientsecret": "..."
},
"abap": {
"url": "https://...abap...hana.ondemand.com",
"client": "001"
}
}XSUAA Service Key (direct format):
{
"url": "https://...authentication...hana.ondemand.com",
"clientid": "...",
"clientsecret": "...",
"apiurl": "https://...api...hana.ondemand.com"
}File Handlers
This package provides utility classes for safe file operations:
Error Handling
All service key stores throw typed errors for better error handling:
import {
BtpServiceKeyStore,
FileNotFoundError,
ParseError,
InvalidConfigError
} from '@mcp-abap-adt/auth-stores';
import { STORE_ERROR_CODES } from '@mcp-abap-adt/interfaces';
const serviceKeyStore = new BtpServiceKeyStore('/path/to/keys');
try {
const authConfig = await serviceKeyStore.getAuthorizationConfig('TRIAL');
console.log('Auth config loaded:', authConfig);
} catch (error: any) {
if (error.code === STORE_ERROR_CODES.FILE_NOT_FOUND) {
// File not found - returns null instead of throwing
console.error('Service key file not found:', error.filePath);
} else if (error.code === STORE_ERROR_CODES.PARSE_ERROR) {
// JSON parsing failed or invalid format
console.error('Failed to parse service key:', error.filePath);
console.error('Cause:', error.cause);
} else if (error.code === STORE_ERROR_CODES.INVALID_CONFIG) {
// Required UAA fields missing - returns null instead of throwing
console.error('Invalid config:', error.missingFields);
} else if (error.code === STORE_ERROR_CODES.STORAGE_ERROR) {
// File write/permission error
console.error('Storage operation failed:', error.operation);
console.error('Cause:', error.cause);
} else {
// Generic error
console.error('Unexpected error:', error.message);
}
}Error Types:
FileNotFoundError- Service key file not found (includesfilePath)ParseError- JSON parsing failed or invalid format (includesfilePathandcause)InvalidConfigError- Required configuration fields missing (includesmissingFieldsarray)StorageError- File write or permission error (includesoperationandcause)
Note: Most errors result in null return values rather than exceptions. Only fatal errors (like JSON parsing failures) throw exceptions.
File Handlers
Utility classes for working with files:
JsonFileHandler
import { JsonFileHandler } from '@mcp-abap-adt/auth-stores';
// Load JSON file
const data = await JsonFileHandler.load('TRIAL.json', '/path/to/directory');
// Save JSON file (atomic write)
await JsonFileHandler.save('/path/to/file.json', { key: 'value' });EnvFileHandler
import { EnvFileHandler } from '@mcp-abap-adt/auth-stores';
// Load .env file
const vars = await EnvFileHandler.load('TRIAL.env', '/path/to/directory');
// Save .env file (atomic write, preserves existing variables)
await EnvFileHandler.save('/path/to/file.env', {
KEY1: 'value1',
KEY2: 'value2'
}, true); // preserveExisting = trueUtilities
Constants
import {
ABAP_AUTHORIZATION_VARS,
ABAP_CONNECTION_VARS,
BTP_AUTHORIZATION_VARS,
BTP_CONNECTION_VARS,
XSUAA_AUTHORIZATION_VARS,
XSUAA_CONNECTION_VARS
} from '@mcp-abap-adt/auth-stores';Service Key Loaders
import { loadServiceKey, loadXSUAAServiceKey } from '@mcp-abap-adt/auth-stores';
// Load ABAP service key (auto-detects format)
const abapKey = await loadServiceKey('TRIAL', '/path/to/service-keys');
// Load XSUAA service key
const xsuaaKey = await loadXSUAAServiceKey('mcp', '/path/to/service-keys');Debug Logging
Stores support optional logging through the ILogger interface. To enable detailed logging:
Using Logger in Code
import { AbapServiceKeyStore } from '@mcp-abap-adt/auth-stores';
import type { ILogger } from '@mcp-abap-adt/interfaces';
// Create logger (or use your own implementation)
const logger: ILogger = {
debug: (msg) => console.debug(msg),
info: (msg) => console.info(msg),
warn: (msg) => console.warn(msg),
error: (msg) => console.error(msg),
};
// Pass logger to store constructor
const store = new AbapServiceKeyStore('/path/to/service-keys', logger);
const sessionStore = new AbapSessionStore('/path/to/sessions', logger);Using Test Logger in Tests
For tests, use the createTestLogger helper which respects environment variables:
import { createTestLogger } from './__tests__/helpers/testLogger';
// Logger will output only if DEBUG_AUTH_STORES=true is set
const logger = createTestLogger('MY-TEST');
const store = new AbapServiceKeyStore('/path/to/service-keys', logger);Environment Variables
To enable logging in tests or when using createTestLogger:
# Enable logging for auth stores (short name)
DEBUG_STORES=true npm test
# Or use long name (backward compatibility)
DEBUG_AUTH_STORES=true npm test
# Or enable via general DEBUG variable
DEBUG=true npm test
# Or include in DEBUG list
DEBUG=stores npm test
# Or
DEBUG=auth-stores npm test
# Set log level (debug, info, warn, error)
LOG_LEVEL=debug npm testNote: Logging requires explicit enable via environment variables. Both DEBUG_STORES (short) and DEBUG_AUTH_STORES (long) are supported for backward compatibility.
Logging shows:
- File operations: Which files are read/written, file sizes, file paths
- Parsing operations: Structure of parsed data, validation results, keys found
- Storage operations: What data is saved/loaded, token lengths, refresh token presence, URLs
- Token formatting: Tokens are logged in truncated format (start...end) for security and readability
- Errors: Detailed error information with context
Logging Features:
- Token Formatting: Tokens are logged in truncated format (start...end) for security
- Structured Logging: Uses
DefaultLoggerfrom@mcp-abap-adt/loggerfor proper formatting with icons and level prefixes - Log Levels: Controlled via
LOG_LEVELorAUTH_LOG_LEVELenvironment variable (error, warn, info, debug)
Example output with DEBUG_STORES=true LOG_LEVEL=debug:
[INFO] ℹ️ [TEST-STORE] Reading service key file: /path/to/TRIAL.json
[DEBUG] 🐛 [TEST-STORE] File read successfully, size: 121 bytes, keys: uaa
[DEBUG] 🐛 [TEST-STORE] Parsed service key structure: hasUaa(true), uaaKeys(url, clientid, clientsecret)
[INFO] ℹ️ [TEST-STORE] Authorization config loaded from /path/to/TRIAL.json: uaaUrl(https://...authentication...), clientId(test-client...)
[DEBUG] 🐛 [TEST-STORE] Reading env file: /path/to/TRIAL.env
[DEBUG] 🐛 [TEST-STORE] Env file read successfully, size: 245 bytes
[INFO] ℹ️ [TEST-STORE] Session loaded for TRIAL: token(2263 chars, eyJ0eXAiOiJKV1QiLCJqaWQiO...Q5ti7aYmEzItIDuLp7axNYo6w), refreshToken(fcc971e1cf1548629216a96b0680eb85-r), sapUrl(https://...abap...)Note: Logging only works when a logger is explicitly provided. Stores will not output anything to console if no logger is passed.
Testing
The package includes both unit tests (with mocked file system) and integration tests (with real files).
Unit Tests
Unit tests use Jest with mocked file system operations:
npm testIntegration Tests
Integration tests work with real files from tests/test-config.yaml:
- Copy
tests/test-config.yaml.templatetotests/test-config.yaml - Fill in real paths and destinations
- Run tests - integration tests will use real files if configured
auth_broker:
paths:
service_keys_dir: ~/.config/mcp-abap-adt/service-keys/
sessions_dir: ~/.config/mcp-abap-adt/sessions/
abap:
destination: "TRIAL"
xsuaa:
btp_destination: "mcp"
mcp_url: "https://..."Integration tests will skip if test-config.yaml is not configured or contains placeholder values.
Architecture
File Operations
- Service Key Stores use
JsonFileHandlerto read JSON files - Session Stores use
EnvFileHandlerto read/write.envfiles - All file writes are atomic (write to temp file, then rename)
Store Implementation
- All stores implement
IServiceKeyStoreorISessionStoreinterfaces from@mcp-abap-adt/interfaces - Stores accept a single directory path in constructor
- File-based session stores automatically create directories in constructor if they don't exist
- Session stores automatically create sessions when calling
setConnectionConfigorsetAuthorizationConfig(no need to callsaveSessionfirst) - In-memory stores (
Safe*SessionStore) don't persist data to disk
Session Store Behavior
Session stores are designed to work seamlessly with AuthBroker:
- Ready after construction: File-based stores create directory automatically, stores are ready to use immediately
- Automatic session creation: Calling
setConnectionConfigorsetAuthorizationConfigon an empty store creates a new session - ABAP stores: Require
serviceUrlwhen creating new session (from config ordefaultServiceUrlparameter) - BTP/XSUAA stores: Require
defaultServiceUrlin constructor (cannot be obtained from service key), used when creating new sessions ifconfig.serviceUrlis not provided - Token updates:
setConnectionConfigupdates token if provided, preserves existing token if not provided - Session updates: When updating existing sessions, only
config.serviceUrlis used if explicitly provided;defaultServiceUrlis never used to modify existing sessions
Dependencies
@mcp-abap-adt/interfaces(^0.1.4) - Interface definitions (IServiceKeyStore,ISessionStore,IConfig,IConnectionConfig,IAuthorizationConfig,ILogger)dotenv- Environment variable parsing
License
MIT
