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

@marianfoo/sap-mcp-auth

v0.1.3

Published

Shared SAP IAS browser login and session module for SAP MCP servers (Playwright-based).

Downloads

1,192

Readme

@marianfoo/sap-mcp-auth

Part of the sap-mcp-servers monorepo (npm workspaces) — published to npm independently as @marianfoo/sap-mcp-auth with build provenance.

Shared SAP IAS (accounts.sap.com) browser-login and session module for SAP MCP servers.

It drives a Playwright browser to complete SAP login — username/password, SAP Passport (PFX) certificate, or interactive/manual — captures and caches the resulting session cookies, and returns a structured AuthSession. Service-specific differences (which app URL to open, how to scope cookies, how to validate a session) are supplied through a small ServiceProfile, so the login mechanics live in one place.

Used by its sibling servers in the monorepo: sap-api-hub-mcp, sap-roadmap-mcp, and sap-note-search-mcp. Each supplies a service-specific ServiceProfile to this module's SapWebAuthenticator.

Unofficial. This package is not endorsed by SAP. It automates authenticated SAP web endpoints and browser session cookies in ways that may be restricted by SAP terms of service or your organization's policies. Use at your own risk and only where you are permitted to.

Install

playwright is a peer dependency — install it in your project (the SAP MCP servers already do):

npm install @marianfoo/sap-mcp-auth playwright
npx playwright install chromium

Requires Node.js >= 18 and is published as ESM only.

Quick start

import { SapWebAuthenticator, type AuthConfig, type ServiceProfile } from '@marianfoo/sap-mcp-auth';

const config: AuthConfig = {
  authMethod: 'auto',                 // 'auto' | 'password' | 'certificate' | 'interactive'
  sapUsername: process.env.SAP_USERNAME,
  sapPassword: process.env.SAP_PASSWORD,
  sapLoginUrl: 'https://me.sap.com/home',
  mfaTimeout: 180_000,
  maxSessionAgeH: 12,
  headful: false,                     // set true when MFA / manual login is required
  tokenCacheFile: '/abs/path/token-cache.json',
  ssoStorageStateFile: '/abs/path/.sap-mcp/sso-storage-state.json'
};

const profile: ServiceProfile = {
  serviceName: 'SAP Road Map',
  appUrl: 'https://roadmaps.sap.com/board',                 // optional page that mints app cookies
  cookieScope: { type: 'url', url: 'https://roadmaps.sap.com' },
  expectedHost: 'roadmaps.sap.com',
  // optional: confirm the cookies actually work before trusting them (cache reuse AND fresh login)
  validateSession: async cookieHeader => {
    const res = await fetch('https://roadmaps.sap.com/services/deliverable-search/periods?range=CURRENT-LAST', {
      headers: { cookie: cookieHeader, accept: 'application/json' }
    });
    return res.ok && (res.headers.get('content-type') || '').includes('json');
  }
};

const auth = new SapWebAuthenticator(config, profile);

const session = await auth.ensureSession();
const res = await fetch('https://roadmaps.sap.com/services/deliverable-search/search?q=workflow', {
  headers: { cookie: session.cookieHeader }
});

Retry-on-expiry pattern

Wrap calls so an expired session re-authenticates once. Have your API layer throw an error whose message contains SESSION_EXPIRED / 401 / Unauthorized when the server returns a login page instead of data:

async function withAuthRetry<T>(fn: (cookieHeader: string) => Promise<T>): Promise<T> {
  const { cookieHeader } = await auth.ensureSession();
  try {
    return await fn(cookieHeader);
  } catch (err) {
    if (/SESSION_EXPIRED|401|Unauthorized/.test(String((err as Error)?.message))) {
      auth.invalidateAuth();
      const { cookieHeader: fresh } = await auth.ensureSession();
      return fn(fresh);
    }
    throw err;
  }
}

How it works

  • Single-flight — concurrent ensureSession() callers share one login attempt.
  • Cookie cache — the session is cached to tokenCacheFile (JSON) and reused until it nears expiry (maxSessionAgeH, 5-minute buffer).
  • Shared SSO — after login the Playwright storage state is written to ssoStorageStateFile; other SAP MCP servers seed their browser context from it, so a single SAP login is reused across services. With sharedSsoTokenFastPath: true a valid storage-state file is reused without launching a browser.
  • validateSession gate — when provided, it runs on both cached reuse and fresh login; a rejected session is evicted and re-minted once.
  • Cookie scoping — cookieScope decides which cookies form the header: { type: 'url', url } (origin-scoped), { type: 'domain', includes, fallbackToAll? }, or { type: 'all' }.
  • Credential-origin guard — password login fills credentials only on SAP's public identity origin or the configured standard customer-IAS tenant, and refuses to forward the password when federation changes the origin.

API

new SapWebAuthenticator(config: AuthConfig, profile: ServiceProfile)

| Method | Description | | --- | --- | | ensureSession(): Promise<AuthSession> | Return a valid session, logging in if needed. | | invalidateAuth(): void | Drop the in-memory + on-disk cache; next call re-authenticates. | | loginOnly(): Promise<AuthSession> | Force a fresh login (useful for a HEADFUL=true "mint SSO state" script). | | destroy(): Promise<void> | Reset state and close any browser. |

AuthSession

interface AuthSession {
  cookieHeader: string;       // "name=value; name2=value2" for your API requests
  cookies: Cookie[];          // Playwright cookies, scoped per profile
  expiresAt: number;          // epoch ms
  storageStateFile?: string;  // path to the shared SSO storage state, if configured
  authMethod: 'password' | 'certificate' | 'interactive';
}

ServiceProfile

| Field | Required | Description | | --- | --- | --- | | serviceName | yes | Used in log messages. | | appUrl | no | App page opened after SAP login to mint service-scoped cookies. Omit for me.sap.com-only flows. | | cookieScope | yes | {type:'url',url} | {type:'domain',includes,fallbackToAll?} | {type:'all'}. | | expectedHost | no | Substring the post-login URL must contain before the MFA/redirect wait resolves. | | validateSession | no | (cookieHeader) => Promise<boolean>; gates cached reuse and fresh login. | | authCompletePredicate | no | Override of the "left the auth pages" check during certificate auth. | | userAgent | no | Custom browser user agent. |

AuthConfig

authMethod, sapUsername, sapPassword, pfxPath, pfxPassphrase, sapLoginUrl, mfaTimeout (ms), maxSessionAgeH, headful, tokenCacheFile, ssoStorageStateFile, browserType ('chromium'|'firefox'|'webkit'), launchRetries (default 3), sharedSsoTokenFastPath (default false), logger.

loadAuthConfigFromEnv(options)

Builds an AuthConfig from environment variables (reads both MAX_JWT_AGE_H and MAX_COOKIE_AGE_H for compatibility):

import { loadAuthConfigFromEnv } from '@marianfoo/sap-mcp-auth';

const config = loadAuthConfigFromEnv({
  defaultTokenCacheFile: '/abs/path/token-cache.json',
  tokenCacheEnvVars: ['MY_TOKEN_CACHE_FILE', 'TOKEN_CACHE_FILE'],
  sharedSsoTokenFastPath: false,
  logger: myLogger
});

| Env var | Meaning | | --- | --- | | AUTH_METHOD | auto (default) | password | certificate | interactive | | SAP_USERNAME, SAP_PASSWORD | Username/password auth | | PFX_PATH, PFX_PASSPHRASE | SAP Passport / client-certificate auth | | SAP_LOGIN_URL | Login start page (default https://me.sap.com/home) | | HEADFUL | true shows the browser (needed for MFA / interactive) | | MFA_TIMEOUT | ms to wait for MFA / redirect (default 180000) | | MAX_JWT_AGE_H / MAX_COOKIE_AGE_H | Cache lifetime in hours (default 12) | | SAP_SSO_STORAGE_STATE | Path to the shared SSO storage-state file | | PLAYWRIGHT_BROWSER_TYPE | chromium (default) | firefox | webkit |

When loading configuration from a .env file, quote any value containing #; dotenv otherwise treats # and everything after it as a comment. For example, use SAP_PASSWORD="My#Pass". The same applies to PFX_PASSPHRASE.

Customer IAS and corporate identity providers

Direct password login supports the standard SAP Cloud Identity Services tenant domains *.accounts.ondemand.com, *.accounts.cloud.sap, and *.accounts.sapcloud.cn. Set SAP_LOGIN_URL to the intended tenant's HTTPS URL; only that exact tenant origin and https://accounts.sap.com are allowed to receive credentials. Custom IAS domains require interactive login. The authenticator waits for the JavaScript redirect used by an unauthenticated tenant /admin entry page before detecting the credential form.

If conditional authentication delegates the login to a corporate identity provider, the password flow fails closed before filling SAP_PASSWORD on the new origin. Corporate federation can require different credentials, MFA, passkeys, or organization-specific policies and must be completed through a separate interactive login flow. The authenticator never assumes that SAP_PASSWORD is valid for the delegated identity provider.

Also exported

isOnAuthPage, isAuthUrl, selectCookies, serializeCookies, defaultLogger, and the error classes AuthenticationError, CertificateLoadError, AuthenticationTimeoutError, BrowserNotFoundError. The Logger interface lets you inject your own logger ({ warn, error, info, debug }); a stderr defaultLogger is used otherwise.

Security

The tokenCacheFile and the SSO storageStateFile contain live SAP session cookies. Treat them as secrets: store them outside your repo (e.g. ~/.sap-mcp/), never commit them, and add them to .gitignore. Credentials and passphrases are never written to these files, but the cookies they hold can be used to act as you on SAP services until they expire.

Finding and recovering cached sessions

For MCP clients, set the shared-state path and each service's token-cache path to explicit absolute paths outside node_modules. The resolved paths are logged at startup, without cookie contents.

| State | Override | Default when unset | | --- | --- | --- | | Shared SSO | SAP_SSO_STORAGE_STATE | ~/.sap-mcp/sso-storage-state.json in the user's home | | API Hub | API_HUB_TOKEN_CACHE_FILE (then TOKEN_CACHE_FILE) | api-hub-token-cache.json in the process working directory | | Road Map | ROADMAP_TOKEN_CACHE_FILE (then TOKEN_CACHE_FILE) | roadmap-token-cache.json in the process working directory | | Notes | SAP_NOTES_TOKEN_CACHE_FILE (then TOKEN_CACHE_FILE) | token-cache.json in the installed Notes package directory |

Create the parent directory, not an empty state file. Malformed state is ignored during login; it is replaced only after a successful, service-validated login. Rejected service caches trigger fresh authentication. A temporary validation outage is reported and preserves the cached session.

If login needs MFA, run once with HEADFUL=true and complete the browser login. Notes honors this on Windows and when launched over stdio. Explicit DOCKER_ENV=true or CI=true still forces its browser to run headless. Use the same absolute SSO path when returning to the MCP client.

Tests

Run npm test -w @marianfoo/sap-mcp-auth from the repository root for unit tests. For browser regressions, install Chromium with npx playwright install chromium, then run npm run test:browser -w @marianfoo/sap-mcp-auth. These tests use synthetic credentials and locally served forms to verify allowed origins, delegated login rejection, and the tenant admin redirect.

License

Apache-2.0