npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@babamba2/mcp-abap-adt-auth-providers

v1.0.5

Published

Token providers for MCP ABAP ADT auth-broker (fork of @mcp-abap-adt/auth-providers by fr0ster)

Readme

@mcp-abap-adt/auth-providers

Token providers for MCP ABAP ADT auth-broker.

This package provides token provider implementations for the @mcp-abap-adt/auth-broker package.

Installation

npm install @mcp-abap-adt/auth-providers

Overview

This package implements the ITokenProvider interface from @mcp-abap-adt/interfaces:

  • AuthorizationCodeProvider - Uses browser-based OAuth2 authorization code flow (user token)
  • ClientCredentialsProvider - Uses client_credentials grant type (no browser required)

Providers are configured via constructor; getTokens() takes no parameters and handles refresh/login internally.

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: Providers are decoupled from concrete implementations in other packages
  • Flexibility: New implementations can be added without modifying providers
  • Testability: Easy to mock dependencies for testing
  • Maintainability: Changes to implementations don't affect providers

Package Responsibilities

This package is responsible for:

  1. Implementing token provider interface: Provides concrete implementations of ITokenProvider interface defined in @mcp-abap-adt/interfaces
  2. Token acquisition: Handles OAuth2 flows (browser-based, refresh token, client credentials) to obtain JWT tokens
  3. Token validation: Validates JWT locally by checking exp claim (no HTTP requests)
  4. OAuth2 flows: Manages browser-based OAuth2 authorization code flow and refresh token flow

What This Package Does

  • Implements ITokenProvider: Provides concrete implementations (AuthorizationCodeProvider, ClientCredentialsProvider)
  • Handles OAuth2 flows: Browser-based OAuth2, refresh token, and client credentials grant types
  • Obtains tokens: Makes HTTP requests to UAA endpoints to obtain JWT tokens
  • Validates tokens: Validates JWT locally by checking exp claim (no HTTP requests)
  • Returns tokens: Returns ITokenResult with authorizationToken and optional refreshToken

What This Package Does NOT Do

  • Does NOT store tokens: Token storage is handled by @mcp-abap-adt/auth-stores
  • Does NOT orchestrate authentication: Token lifecycle management is handled by @mcp-abap-adt/auth-broker
  • Does NOT know about service keys: Service key loading is handled by stores
  • Does NOT manage sessions: Session management is handled by stores
  • Does NOT return serviceUrl if unknown: Providers may not return serviceUrl because they only handle token acquisition, not connection configuration

External Dependencies

This package interacts with external packages ONLY through interfaces:

  • @mcp-abap-adt/auth-broker: Uses interfaces (ITokenProvider, IAuthorizationConfig) - does not know about AuthBroker implementation
  • @mcp-abap-adt/logger: Uses Logger interface for logging - does not know about concrete logger implementation
  • @mcp-abap-adt/connection: Uses connection utilities for token validation - interacts through well-defined functions
  • No direct dependencies on stores: All interactions with stores happen through interfaces passed by consumers

Usage

Basic Usage

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { AuthorizationCodeProvider, ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';

// User token via authorization_code (browser flow)
const authCodeBroker = new AuthBroker({
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
  }),
});

// Service token via client_credentials (no browser)
const clientCredsBroker = new AuthBroker({
  tokenProvider: new ClientCredentialsProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
  }),
}, 'none');

SSO Providers

This package also includes SSO providers for OIDC and SAML2, plus a small factory for DI-friendly creation.

Available providers:

  • OidcBrowserProvider (authorization code + PKCE)
  • OidcDeviceFlowProvider
  • OidcPasswordProvider
  • OidcTokenExchangeProvider
  • Saml2BearerProvider (SAML assertion exchange)
  • Saml2PureProvider (returns SAMLResponse as token)

Factory example:

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { SsoProviderFactory } from '@mcp-abap-adt/auth-providers';

const tokenProvider = SsoProviderFactory.create({
  protocol: 'oidc',
  flow: 'browser',
  config: {
    issuerUrl: 'https://example-idp/.well-known/openid-configuration',
    clientId: '...',
    clientSecret: '...',
    scopes: ['openid', 'profile', 'email'],
    browser: 'system',
  },
});

const broker = new AuthBroker({ tokenProvider }, 'none');

OIDC browser example (manual code + explicit endpoints):

import { OidcBrowserProvider } from '@mcp-abap-adt/auth-providers';

const provider = new OidcBrowserProvider({
  clientId: '...',
  tokenEndpoint: 'https://issuer/oauth/token',
  authorizationEndpoint: 'https://issuer/oauth/authorize',
  authorizationCode: '<paste-code-here>',
  redirectUri: 'urn:ietf:wg:oauth:2.0:oob',
});

SAML bearer example (manual flow):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2BearerProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2BearerProvider({
  assertionFlow: 'manual',
  idpSsoUrl: 'https://idp.example.com/sso',
  spEntityId: 'my-sp-entity',
  uaaUrl: 'https://uaa.example.com',
  clientId: '...',
  clientSecret: '...',
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

SAML bearer example (headless, assertion provider):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2BearerProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2BearerProvider({
  assertionFlow: 'assertion',
  assertionProvider: async () => {
    return getSamlResponseFromSsoProxy();
  },
  uaaUrl: 'https://uaa.example.com',
  clientId: '...',
  clientSecret: '...',
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

Pure SAML example (cookie-based):

import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { Saml2PureProvider } from '@mcp-abap-adt/auth-providers';

const provider = new Saml2PureProvider({
  assertionFlow: 'manual',
  idpSsoUrl: 'https://idp.example.com/sso',
  spEntityId: 'my-sp-entity',
  // Convert SAMLResponse to session cookies for SAP (implementation-specific)
  cookieProvider: async (samlResponse) => {
    return exchangeSamlForCookies(samlResponse);
  },
});

const broker = new AuthBroker({ tokenProvider: provider }, 'none');

With Stores

Important: BTP and ABAP are different entities:

  • BTP (base BTP) - uses BtpServiceKeyStore and BtpSessionStore (without sapUrl)
  • ABAP - uses AbapServiceKeyStore and AbapSessionStore (with sapUrl)
import { AuthBroker } from '@mcp-abap-adt/auth-broker';
import { AuthorizationCodeProvider, ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';
import { 
  XsuaaServiceKeyStore, 
  XsuaaSessionStore,
  BtpServiceKeyStore,
  BtpSessionStore,
  AbapServiceKeyStore,
  AbapSessionStore 
} from '@mcp-abap-adt/auth-stores';

// XSUAA provider with stores (client_credentials or auth code)
const xsuaaServiceKeyStore = new XsuaaServiceKeyStore('/path/to/service-keys');
const xsuaaSessionStore = new XsuaaSessionStore('/path/to/sessions');

const xsuaaBroker = new AuthBroker({
  serviceKeyStore: xsuaaServiceKeyStore,
  sessionStore: xsuaaSessionStore,
  tokenProvider: new ClientCredentialsProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
  }),
}, 'none');

// BTP provider with stores (base BTP, without sapUrl)
const btpServiceKeyStore = new BtpServiceKeyStore('/path/to/service-keys');
const btpSessionStore = new BtpSessionStore('/path/to/sessions');

const btpBroker = new AuthBroker({
  serviceKeyStore: btpServiceKeyStore,
  sessionStore: btpSessionStore,
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
  }),
});

// ABAP provider with stores (with sapUrl)
const abapServiceKeyStore = new AbapServiceKeyStore('/path/to/service-keys');
const abapSessionStore = new AbapSessionStore('/path/to/sessions');

// Use custom port if running alongside other services (e.g., proxy on port 3001)
const abapBroker = new AuthBroker({
  serviceKeyStore: abapServiceKeyStore,
  sessionStore: abapSessionStore,
  tokenProvider: new AuthorizationCodeProvider({
    uaaUrl: 'https://...',
    clientId: '...',
    clientSecret: '...',
    browser: 'system',
    redirectPort: 4001,
  }), // Custom port to avoid conflicts
});

Token Providers

AuthorizationCodeProvider

Uses browser-based OAuth2 flow or refresh token:

import { AuthorizationCodeProvider } from '@mcp-abap-adt/auth-providers';

const provider = new AuthorizationCodeProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
  browser: 'system',
});

// If refreshToken is provided here, uses refresh flow (no browser)
// Otherwise, opens browser for OAuth2 authorization
const result = await provider.getTokens();

// result.authorizationToken contains the JWT token
// result.refreshToken contains refresh token (if browser flow was used)

ClientCredentialsProvider

Uses client_credentials grant type - no browser interaction required:

import { ClientCredentialsProvider } from '@mcp-abap-adt/auth-providers';

const provider = new ClientCredentialsProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
});

const result = await provider.getTokens();

// result.authorizationToken contains the JWT token
// result.refreshToken is undefined (client_credentials doesn't provide refresh tokens)

Note: The browserAuthPort parameter (default: 3001) configures the OAuth callback server port. If the requested port is already in use, an error will be thrown. You must specify a different port or free the port before starting authentication. The server properly closes all connections and frees the port after authentication completes, ensuring no lingering port occupation.

Timeout: Browser authentication has a 30-second timeout to prevent blocking the consumer. If authentication is not completed within 30 seconds, the operation will fail with a timeout error. This prevents the provider from hanging indefinitely when the user doesn't complete authentication.

Process Termination Handling: The OAuth callback server registers cleanup handlers for SIGTERM, SIGINT, SIGHUP, and exit signals. This ensures ports are properly freed even when MCP clients (like Cline) terminate the process before authentication completes. This is especially important for stdio servers where the client may kill the process at any time. On Windows, the SIGBREAK signal (Ctrl+Break) is also handled.

Cross-Platform Browser Support: The browser authentication works across Linux, macOS, and Windows:

  • Linux: Automatically sets DISPLAY=:0 if neither DISPLAY nor WAYLAND_DISPLAY environment variables are set. Supports multiple browser executable names (google-chrome, google-chrome-stable, chromium, chromium-browser for Chrome; firefox, firefox-esr for Firefox).
  • Windows: Uses proper cmd /c start "" syntax for reliable browser opening.
  • macOS: Uses native open -a command.

Headless Mode (SSH/Remote): For environments without a display (SSH sessions, Docker, CI/CD), use browser: 'headless':

const result = await provider.getTokens();

In headless mode, the authentication URL is logged and the server waits for the user to complete authentication manually. The user can open the URL on any machine and the callback will be received by the server.

Browser Options:

  • 'system' (default): Opens system default browser
  • 'headless': Logs URL, waits for manual callback (SSH/remote)
  • 'none': Logs URL, immediately rejects (automated tests)
  • 'chrome', 'edge', 'firefox': Opens specific browser

Token Validation

Providers can perform local JWT validation by checking the exp (expiration) claim:

const isValid = await provider.validateToken(token, serviceUrl);
  • No HTTP requests are made to the SAP server
  • Returns true if token has valid JWT format and exp is in the future (with 60s buffer)
  • Returns false if token is expired, invalid format, or will expire within 60 seconds
  • Network issues (ECONNREFUSED, timeout) do NOT trigger token refresh
  • HTTP errors (401/403) are handled by retry mechanism in makeAdtRequest wrapper
// Local validation (no HTTP)
const provider = new AuthorizationCodeProvider({
  uaaUrl: 'https://...authentication...hana.ondemand.com',
  clientId: '...',
  clientSecret: '...',
});
const isValid = await provider.validateToken(token);  // serviceUrl optional
// Checks JWT exp claim locally, no network request

This approach prevents unnecessary token refresh and browser authentication when:

  • Server is unreachable (ECONNREFUSED, timeout)
  • Network is slow or unstable
  • Running in offline/disconnected mode

Token Refresh

Providers handle refresh automatically inside getTokens(). No separate refresh methods are needed.

try {
  const result = await provider.getTokens();
  // Returns new access token and refresh token (if available)
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Missing fields:', error.missingFields);
  } else if (error instanceof RefreshError) {
    console.error('Browser auth failed:', error.cause);
  }
}

Error Handling

The package provides typed error classes for better error handling:

import {
  TokenProviderError,
  ValidationError,
  RefreshError,
  SessionDataError,
  ServiceKeyError,
  BrowserAuthError,
} from '@mcp-abap-adt/auth-providers';

try {
  const result = await provider.getTokens();
} catch (error) {
  if (error instanceof ValidationError) {
    // provider config validation failed
    console.error('Missing required fields:', error.missingFields);
    console.error('Error code:', error.code); // 'VALIDATION_ERROR'
  } else if (error instanceof RefreshError) {
    // Token refresh operation failed
    console.error('Refresh failed:', error.message);
    console.error('Original error:', error.cause);
    console.error('Error code:', error.code); // 'REFRESH_ERROR'
  } else if (error instanceof BrowserAuthError) {
    // Browser authentication failed
    console.error('Browser auth failed:', error.cause);
  }
}

Error Types:

  • TokenProviderError - Base class with code: string property
  • ValidationError - provider config validation failed, includes missingFields: string[]
  • RefreshError - Token refresh failed, includes cause?: Error
  • SessionDataError - Session data invalid, includes missingFields: string[]
  • ServiceKeyError - Service key data invalid, includes missingFields: string[]
  • BrowserAuthError - Browser auth failed, includes cause?: Error

All error codes are defined in @mcp-abap-adt/interfaces package as TOKEN_PROVIDER_ERROR_CODES.

Testing

The package includes both unit tests (with mocks) and integration tests (with real files and services).

Unit Tests

npm test

Integration Tests

Integration tests work with real files from tests/test-config.yaml:

  1. Copy tests/test-config.yaml.template to tests/test-config.yaml
  2. Fill in real destination name
  3. Run tests - integration tests will use real services if configured
# Destination name (used for service key file: <destination>.json and session file: <destination>.env)
destination: "trial"  # Example: "trial" -> looks for trial.json and trial.env

# Optional: Destination directory (base directory for service keys and sessions)
# If not specified, uses default platform paths:
#   Unix: ~/.config/mcp-abap-adt
#   Windows: %USERPROFILE%\Documents\mcp-abap-adt
# Uncomment and set if you need a custom path:
# destination_dir: ~/.config/mcp-abap-adt

Integration tests will skip if test-config.yaml is not configured or contains placeholder values.

Test Scenarios:

  • Scenario 1 & 2: Token lifecycle - login via browser and reuse token from previous scenario
  • Scenario 3: Expired session + expired refresh token - provider should re-authenticate via browser
  • Token validation: Explicit validation of token expiration in all scenarios

Note:

  • Integration tests use AbapServiceKeyStore and AbapSessionStore for loading service keys and sessions
  • Tests may open a browser for authentication if no refresh token is available. This is expected behavior.
  • Each test scenario uses a unique port (3101, 3102, 3103) to avoid port conflicts
  • Tests use browser: 'system' for interactive authentication (not 'none')

Debug Logging

To enable detailed logging during tests or runtime, set environment variables:

# Enable logging for auth providers (short name)
DEBUG_PROVIDER=true npm test

# Or use long name (backward compatibility)
DEBUG_AUTH_PROVIDERS=true npm test

# Or enable via general DEBUG variable
DEBUG=true npm test

# Or include in DEBUG list
DEBUG=provider npm test
# Or
DEBUG=auth-providers npm test

# Set log level (debug, info, warn, error)
LOG_LEVEL=debug npm test

Logging uses @mcp-abap-adt/logger package with structured logging:

  • Token exchange stages (what we send, what we receive)
  • Token information (lengths, previews, expiration)
  • Token validation checks (expiration, validity)
  • Errors with details

Example output:

[INFO] ℹ️ [browserAuth] Exchanging code for token...
[INFO] ℹ️ Tokens received: accessToken(2263 chars), refreshToken(34 chars)
[DEBUG] 🐛 [BaseTokenProvider] Token validation check {"expiresAt":"2025-12-25 11:08:15 UTC","isValid":true}
[INFO] ℹ️ [browserAuth] Authorization URL: https://.../oauth/authorize?...
[INFO] ℹ️ [browserAuth] Browser: system

Logging Features:

  • Token Formatting: Tokens are logged in truncated format (start...end) for security
  • Date Formatting: Expiration dates are displayed in readable format (YYYY-MM-DD HH:MM:SS UTC) instead of ISO format
  • Browser Information: Logs browser type and authorization URL for debugging
  • Token Lifecycle: Detailed logging of token acquisition, validation, and refresh operations

Dependencies

  • @mcp-abap-adt/interfaces (^0.2.2) - Interface definitions and error code constants
  • axios - HTTP client
  • express - OAuth2 callback server
  • open - Browser opening utility

License

MIT