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

@saptools/cf-xsuaa

v0.1.10

Published

Fetch XSUAA credentials and OAuth2 access tokens from SAP BTP Cloud Foundry apps

Readme

🔐 @saptools/cf-xsuaa

Stop copy-pasting XSUAA tokens from the BTP cockpit.

Fetch XSUAA credentials and OAuth2 access tokens from SAP BTP Cloud Foundry apps — straight from your terminal, with intelligent caching built in.

npm version license node install size types

InstallQuick StartCLIAPIFAQ


✨ Features

  • 🔑 Zero-config OAuth2 — fetches client_credentials tokens straight from the XSUAA binding of any CF app
  • 💾 Smart caching — reuses tokens until they expire so you do not hand out stale JWTs
  • 🧩 CLI & API — drop into shell scripts, Node pipelines, or your favorite test runner
  • 🔗 CF-aware — resolves CF API endpoints from region keys via @saptools/cf-sync, no manual URLs
  • 🔒 Type-safe — shipped with full TypeScript definitions
  • 🪶 Tiny — one dependency (commander) and zero runtime magic

📦 Install

# Global CLI
npm install -g @saptools/cf-xsuaa

# Or as a dependency
npm install @saptools/cf-xsuaa
# pnpm add @saptools/cf-xsuaa
# yarn add @saptools/cf-xsuaa

[!NOTE] Requires Node.js ≥ 20 and the cf CLI on PATH. For the first secret fetch, set SAP_EMAIL and SAP_PASSWORD.


🚀 Quick Start

# 1. Tell cf-xsuaa who you are (only needed for the first secret fetch)
export SAP_EMAIL="[email protected]"
export SAP_PASSWORD="your-sap-password"

# 2. Grab a token (auto-fetches the XSUAA binding on first call, caches it forever)
cf-xsuaa get-token-cached \
  --region ap10 --org my-org --space dev --app my-srv

That's it. Copy the printed JWT into curl, Postman, bruno, or wherever you need it. Next call reuses the cached token until it expires.


🧰 CLI

Every command identifies an app with the same four flags:

| Flag | Description | Example | | --- | --- | --- | | -r, --region <key> | CF region key | ap10, eu10, us10 | | -o, --org <name> | CF org name | my-org | | -s, --space <name> | CF space name | dev | | -a, --app <name> | CF app name | my-srv |

🔎 cf-xsuaa fetch-secret

Pull the XSUAA client credentials out of the app's VCAP_SERVICES and cache them to disk. Run this once per app, or whenever the binding rotates.

cf-xsuaa fetch-secret --region ap10 --org my-org --space dev --app my-srv

🎟️ cf-xsuaa get-token

Fetch a fresh OAuth2 client_credentials token and print the JWT to stdout. Auto-runs fetch-secret first if the binding isn't cached yet.

cf-xsuaa get-token --region ap10 --org my-org --space dev --app my-srv

cf-xsuaa get-token-cached

Return the cached token if it's still valid, otherwise fetch a new one. This is what you want 99% of the time.

TOKEN=$(cf-xsuaa get-token-cached --region ap10 --org my-org --space dev --app my-srv)
curl -H "Authorization: Bearer $TOKEN" https://my-srv.cfapps.ap10.hana.ondemand.com/api/health

[!TIP] Cached tokens are refreshed before they become stale, so callers do not receive a JWT that is about to expire.


🧑‍💻 Programmatic Usage

import {
  fetchSecret,
  getToken,
  getTokenCached,
  readStore,
  xsuaaDataPath,
} from "@saptools/cf-xsuaa";

const ref = {
  region: "ap10",
  org: "my-org",
  space: "dev",
  app: "my-srv",
} as const;

// One-time: cache the client credentials
await fetchSecret(ref);

// Every call: reuse a cached token when possible
const token = await getTokenCached(ref);

// Or: force a fresh token
const freshToken = await getToken(ref);

// Introspect the cache
const store = await readStore();
console.log(`${store.entries.length} apps cached in ${xsuaaDataPath()}`);

🧪 Dependency injection (great for tests)

await getToken(ref, {
  fetchCredentials: async () => ({
    clientId: "cid",
    clientSecret: "csec",
    url: "https://uaa.example.com",
  }),
  fetchToken: async () => "fake-jwt",
  now: new Date("2026-04-18T00:00:00Z"),
});

| Export | Description | | --- | --- | | fetchSecret(ref) | Cache a freshly-fetched XSUAA binding | | getToken(ref) | Force a new OAuth2 token | | getTokenCached(ref) | Reuse cache, fall through on expiry | | readStore() / writeStore(store) | Read / write the on-disk store | | findEntry(store, ref) | Look up a single entry | | upsertSecret(store, ref, creds) | Merge credentials into a store | | upsertToken(store, ref, token) | Merge a token into a store | | fetchClientCredentialsToken(creds) | Low-level UAA call | | parseXsuaaFromVcap(stdout) | Parse cf env output | | decodeJwtPayload(jwt) | Decode the JWT payload without verification | | computeExpiryIso(jwt) / isExpired(iso) | Expiry math | | xsuaaDataPath() / saptoolsDir() | Resolve on-disk paths |


📁 Output File

All state lives in a single JSON file under your home directory:

~/.saptools/xsuaa-data.json
{
  "version": 1,
  "entries": [
    {
      "region": "ap10",
      "org": "my-org",
      "space": "dev",
      "app": "my-srv",
      "credentials": {
        "clientId": "sb-xsappname!t123",
        "clientSecret": "<redacted>",
        "url": "https://my-org.authentication.ap10.hana.ondemand.com",
        "xsappname": "my-app!t123"
      },
      "token": {
        "accessToken": "eyJhbGciOi...",
        "expiresAt": "2026-04-18T12:34:56.000Z"
      },
      "fetchedAt": "2026-04-18T12:20:00.000Z"
    }
  ]
}

[!IMPORTANT] Prefer the CLI or exported APIs over parsing this file directly — the on-disk format is an implementation detail.


❓ FAQ

No. Those are only read when cf-xsuaa has to refresh the VCAP-bound client secret. Once the secret is cached, token refreshes go straight to the UAA with client_credentials — no SAP user credentials required.

cf oauth-token returns your personal UAA token. cf-xsuaa returns the app's own service token (issued to the XSUAA clientId in VCAP_SERVICES), which is what you actually need when calling the app's protected endpoints.

No. ~/.saptools/xsuaa-data.json contains clientSecret and live JWTs. It lives under your home directory and should never be checked into git.

Run cf-xsuaa fetch-secret again with the same --region/--org/--space/--app flags and the entry will be overwritten.


🛠️ Development

From the monorepo root:

pnpm install
pnpm --filter @saptools/cf-xsuaa build
pnpm --filter @saptools/cf-xsuaa typecheck
pnpm --filter @saptools/cf-xsuaa test:unit
pnpm --filter @saptools/cf-xsuaa test:e2e

The e2e suite auto-discovers a real CF app with an xsuaa service binding by scoring candidates from ~/.saptools/cf-structure.json. To pin a specific target:

export E2E_TARGET="ap10/my-org/my-space/my-srv"

🌐 Related


👨‍💻 Author

dongtran

📄 License

MIT


Made with ❤️ to make your work life easier!