@marianfoo/sap-mcp-auth
A shared browser-login and session module for SAP MCP servers: it drives a PlaywrightPlaywrightA library that drives Chromium, Firefox and WebKit from code, written for end-to-end browser testing. For the things here it is the browser a tool starts itself, to get through an SAP login or to load a page headless and photograph it. browser through SAP Identity Authentication, caches the session cookies and returns a cookie header an HTTP client can send.
Three MCP servers in the same monorepo read official SAP sources from behind an SAP login: sap-api-hub-mcpsap-api-hub-mcpA read-only MCP server over the SAP Business Accelerator Hub catalogue: categories, search, metadata, resources, specs and packages, reached as the caller's own SAP user.independent, btp, sap-roadmap-mcpsap-roadmap-mcpAn MCP server over SAP Road Map Explorer, so an agent can read what SAP has announced as planned rather than inferring it from a release that has shipped.independent, btp and sap-note-search-mcpsap-note-search-mcpAn MCP server over SAP Notes and Knowledge Base articles: search finds a note, fetch returns it whole, and a scripted browser does the S-user login the content sits behind.independent, btp. This is the one place that login lives. It drives a PlaywrightPlaywrightA library that drives Chromium, Firefox and WebKit from code, written for end-to-end browser testing. For the things here it is the browser a tool starts itself, to get through an SAP login or to load a page headless and photograph it. browser through SAP Identity Authentication at accounts.sap.com by username and password, by an SAP Passport PFX certificate, or interactively when a multi-factor code is needed, and returns an AuthSession carrying a cookieHeader, the scoped cookies, the expiry and the method used. What differs per service, which page to open, how to scope the cookies and how to check that a session still works, arrives in a ServiceProfile; concurrent callers share one login attempt, cookies are cached until they near expiry, and a shared storage-state file lets one SAP login serve all three servers. It stops at the session: nothing in it calls an SAP API or reads a page, and the maintainer states that the token cache and the storage-state file hold live SAP session cookies and are to be treated as secrets.
Facts
Where it sits
Who is behind it
In the atlas: maintains 35, contributes to 86, wrote 25@marianfoomaintaineradam0thmanContributes to this
In the atlas: maintains 1, contributes to 3@adam0thmanDavid SlugaContributes to this
In the atlas: contributes to 4@army1132 contributors
Before choosing this
Conditions
PracticalFunctional boundary
The maintainer states it is unofficial, not endorsed by SAP, and that it automates authenticated SAP web endpoints and browser session cookies in ways SAP's terms of service or an organisation's own policies may restrict. Password login is confined to accounts.sap.com and the standard SAP Cloud Identity Services tenant domains: a custom IAS domain, or a login that conditional authentication delegates to a corporate identity provider, fails closed before the password is filled and has to be completed through an interactive login instead.
What it declares
Every artifact
- Type
- Package
- Origin
- Independently maintained
- Runtime
- Node.js
As a package
- Where it runs
- In your own program
- Distributed through
- npm
Connections
Establishing who is calling and making that identity available
Identity Authentication and Identity Provisioning as one tenant
A library that drives Chromium, Firefox and WebKit from code, written for end-to-end browser testing. For the things here it is the browser a tool starts itself, to get through an SAP login or to load a page headless and photograph it.
Download
Install
npm add @marianfoo/sap-mcp-authDerived from the package name. No recipe recorded; the README has the configuration.
Where it sits in your app
Download
README
quoted from marianfoo/sap-mcp-servers under Apache-2.0, read@marianfoo/sap-mcp-auth
Part of the sap-mcp-servers monorepo (npm workspaces) — published to npm independently as
@marianfoo/sap-mcp-authwith 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. WithsharedSsoTokenFastPath: truea valid storage-state file is reused without launching a browser. validateSessiongate — when provided, it runs on both cached reuse and fresh login; a rejected session is evicted and re-minted once.- Cookie scoping —
cookieScopedecides 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
History
Features 1, Fixes 4
Notes
Features
Bug Fixes
- auth: recover malformed SSO state and validate Notes sessions (#87) (565145c)
- deps: refresh SDK and vulnerable dependency resolutions (#83) (e20284b)
- enforce IAS login origin boundaries (#49) (cee93e2)
- shared SSO state path on Windows, real notes version, keep SSO state on session expiry (#81) (b9ffee1)
Others providing
Compare all 10 on the Authentication page →- @arc-mcp/xsuaa-auth@arc-mcp/xsuaa-authThe client-to-server authentication stack for an MCP server on SAP BTP: an XSUAA OAuth proxy, dynamic client registration, a chained bearer verifier, and a separate entrypoint for per-user principal propagation.independent, btpXSUAA authentication stack for an MCP server on SAP BTP
- SAP Authorization and Trust Management serviceSAP Authorization and Trust Management serviceThe OAuth server behind a BTP application: issues the JWT the app checks, holds the scopes and role collections it checks against, and brokers trust to an identity provider. Bound, never installed.sap official, btpOAuth server issuing JWTs and holding scopes for BTP apps
- Cloud Identity ServicesCloud Identity ServicesIdentity Authentication and Identity Provisioning as one tenant: the login, the user store or the federation to a corporate identity provider, and the provisioning of users into whatever sits behind it.sap official, btpIdentity Authentication and Identity Provisioning as one tenant
- SAP Customer Identity and Access Management for B2CSAP Customer Identity and Access Management for B2CSAP's customer identity service: registration, login and consent for the users of a company's websites and apps, kept in one profile per customer, with regional data storage and risk-based authentication as options.sap official, btpRegistration, login and consent for customer-facing sites
- OAuth 2.0 on SAP BTPOAuth 2.0 on SAP BTPOAuth 2.0 protection for applications and APIs on SAP BTP, listed in Neo regions: the authorization code grant for web applications and the client credentials grant for API and IoT scenarios.sap official, btpOAuth 2.0 grant flows for applications and APIs in Neo regions
- abap_cloud_platformabap_cloud_platformA TypeScript library of the Cloud Foundry calls that walk down to an ABAP service instance, read its SAP_ADT service key and log a user in, so a tool outside the system can reach it.independent, btpTypeScript library reaching ABAP service instances on Cloud Foundry
- @sap/approuter@sap/approuterSAP's Node.js application router: the single entry point in front of a business application's microservices, which authenticates the user, forwards each request to a backend by route and serves static content.sap official, btpSAP's Node.js application router in front of business applications
- Cloud ConnectorCloud ConnectorSAP's on-premises agent that links SAP BTP applications to systems in a customer's own network, as a reverse invoke proxy that exposes only the systems and resources it is configured to allow.sap official, btpSAP's on-premises agent linking SAP BTP to customer-network systems
- @saptools/cf-xsuaa@saptools/cf-xsuaaA command line and Node.js API that reads the XSUAA binding of a Cloud Foundry app and prints an OAuth2 client_credentials token for it, cached until it expires.independent, btpOAuth2 token fetcher for a Cloud Foundry app's XSUAA binding
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Contributors
History in the atlas
- the module as its README states it, where it runs and how it is installed, and the login edge to the identity service the README names
- Entered with the three servers of the same monorepo that name it. It publishes on its own and answers a question of its own — how a tool outside SAP gets an authenticated session against an SAP portal — so it is an entry rather than an implementation detail of the three.
- First seen.
For your agent
- Ref
artifact:marianfoo-sap-mcp-auth- JSON
- /artifacts/marianfoo-sap-mcp-auth.json
- MCP
- Connecting an agent