Amish Kushwaha - May 10, 2026

The Go toolkit SAP BTP was missing: announcing btp-go

Part 1 of a 5-part series introducing btp-go, a stdlib-only Go toolkit for SAP BTP, released under Apache-2.0.


The setup

If you’ve built anything on SAP BTP, you know the language story: Java and JavaScript/TypeScript are first-class citizens. The SAP Cloud SDK ships in both, with deep integrations for the Destination Service, XSUAA, Cloud Connector, OData generation, the works. CAP โ€” the SAP Cloud Application Programming Model โ€” assumes one of those two runtimes.

Pick anything else, and you’re on your own.

That’s not a hypothetical complaint. We’ve been building Go services on BTP for our own products at BlueFunda โ€” event-driven workers, OData proxies, on-prem bridges โ€” and every time we needed to talk to a re-use service, we hit the same wall: there’s no equivalent toolkit for Go.

So we wrote one. btp-go is a small monorepo of stdlib-only Go libraries for consuming SAP BTP services, released under Apache-2.0. This post explains what’s in the box and why we made the architectural choices we did. The next four posts walk through each subsystem with working code.

What’s actually in the Go ecosystem today

Before we built btp-go, we did the obvious thing โ€” we checked whether someone else had already solved this. Here’s the survey, current as of late 2025:

  • SAP/cloud-security-client-go โ€” Officially maintained. Solves one problem: validating OIDC tokens issued by SAP Identity Authentication Service (IAS), as middleware on the server side of an incoming request. It does not fetch XSUAA tokens, does not look up destinations, does not open Cloud Connector tunnels, and does not parse service bindings beyond IAS itself.
  • SAP-archive/cloud-security-client-golang-xsuaa โ€” XSUAA token validation in Go. The README opens with “This is not an official library (ITS A SAMPLE!!) and therefore is not been maintained in the future.” It’s in the SAP-archive org. That’s the polite way SAP says don’t ship this. And again, validation only โ€” no client-credentials fetching.
  • SAP/cloud-identity-authorizations-golang-library โ€” Client for the newer Cloud Identity Authorization Management Service. Useful if that’s your auth model, irrelevant if you’re integrating XSUAA, the Destination Service, or Cloud Connector.
  • SAP/sap-btp-service-operator โ€” Kubernetes operator for provisioning BTP service instances from a K8s cluster. Operator, not consumer library โ€” entirely different layer.
  • SAP Cloud SDK โ€” Java and JavaScript only. There is no Go port and, as far as anyone has communicated publicly, no plans for one.

Add it up: every Go application that needs to talk to BTP has been writing the same scaffolding from scratch. SOCKS5 dialer with the SAP-specific authentication byte. JWT fetch loop with caching against XSUAA. Destination Service REST client. VCAP_SERVICES parsing. Then the same again for Kyma’s file-mounted bindings, which work nothing like Cloud Foundry’s environment variable.

That scaffolding is what btp-go is.

What’s in the box

btp-go is a Go workspace monorepo with six independently versioned modules:

Module What it does
binding Parses service bindings from VCAP_SERVICES (Cloud Foundry), Kyma’s servicebinding.io file mounts, or auto-detects the runtime
xsuaa Fetches and caches client-credentials access tokens from XSUAA
connectivity Opens TCP tunnels through SAP Cloud Connector via the SOCKS5 proxy (with SAP’s custom 0x80 auth method)
destination Looks up named destinations through the SAP Destination Service REST API
sshclient High-level SSH/SFTP client over the Cloud Connector tunnel โ€” wraps connectivity + destination
httpclient HTTP/REST/OData client wired for a Destination’s auth + Cloud Connector tunnel; includes OData v2 CSRF token helper

The whole thing is stdlib-only. No viper, no zap, no third-party HTTP clients. The one exception is sshclient, which uses golang.org/x/crypto/ssh for SSH โ€” there’s no SSH implementation in the Go standard library, so that’s unavoidable. Everything else is net/http, encoding/json, crypto/tls.

Three design choices worth explaining

1. A monorepo of independent modules

Each subdirectory is its own Go module with its own go.mod and its own semver tag. If your application only needs to fetch XSUAA tokens, you go get github.com/bluefunda/btp-go/xsuaa@latest and nothing else lands in your dependency tree. You don’t pay for SSH if you only need HTTP.

The modules are tied together by a Go workspace (go.work) for local development, so contributors can edit two modules in one IDE session, but consumers see them as six separate libraries.

2. Zero cross-module imports

Look at the dependency graph:

consumer app
    โ”œโ”€โ”€ binding/auto
    โ”œโ”€โ”€ connectivity   (local TokenSource interface)
    โ”œโ”€โ”€ destination    (local TokenSource interface)
    โ”œโ”€โ”€ sshclient      (local Dialer interface)
    โ”œโ”€โ”€ httpclient     (local Dialer + TokenSource interfaces)
    โ””โ”€โ”€ xsuaa

Notice what’s not there: connectivity does not import xsuaa. sshclient does not import connectivity. Each module declares the interfaces it needs locally โ€” a TokenSource here, a Dialer there โ€” and any concrete implementation that satisfies the interface plugs in.

This means you can swap xsuaa for your own token source. You can swap connectivity for a direct net.Dialer in tests, or for a different proxy implementation entirely. The modules compose, but they don’t entangle. Each one is independently auditable, independently testable, and independently versionable.

3. Cloud Foundry and Kyma, one binding API

binding/auto detects at runtime whether the app is running on Cloud Foundry (read VCAP_SERVICES from the environment) or on Kyma (read mounted secret files at /bindings/<name>/). The Kyma reader handles all three layouts the servicebinding.io spec allows โ€” per-key files, JSON-blob fallback, Kubernetes atomic-update sentinel directories โ€” so application code never branches on runtime.

That mattered a lot to us. We don’t want to maintain two integration paths just because BTP exposes credentials differently in two of its own runtimes.

What’s coming in this series

This was the introduction. The next four posts each take one slice of btp-go and walk through it with working code:

  • Part 2 โ€” Foundations: service bindings and XSUAA. What VCAP_SERVICES actually contains, what Kyma puts on disk, how binding/auto picks between them, and how xsuaa caches tokens correctly across concurrent goroutines.
  • Part 3 โ€” Reaching on-prem: Connectivity and Destination. The SAP-specific 0x80 auth byte that no off-the-shelf SOCKS5 client speaks. How destination lookups thread the JWT correctly. Why the two compose.
  • Part 4 โ€” Worked example: counting files in AL11. A complete Cloud Foundry app that uses sshclient to connect through Cloud Connector to an on-prem ABAP system and count files in an AL11 directory. End-to-end: bindings โ†’ xsuaa โ†’ connectivity โ†’ destination โ†’ SFTP.
  • Part 5 โ€” Worked example: HTTP destinations end-to-end. Create a destination programmatically through the Destination Service API. Use it to fetch a public weather feed. Then use it to call an on-prem /sap/opu/odata/iwfnd/CATALOGSERVICE/ Gateway service, with CSRF token handling for the writes.

If you build Go services that need to talk to BTP โ€” or to ABAP systems behind Cloud Connector โ€” clone the repo, browse the examples/ directory, and let us know in GitHub issues what you’d want to see next. M2 (Oracle over connectivity.Dial using go-ora) and M5 (principal propagation in xsuaa) are on the roadmap; we’re prioritizing by what real users hit first.

The repo is at github.com/bluefunda/btp-go. Apache-2.0. Issues and PRs welcome.

Next up โ€” Part 2: Foundations: service bindings and XSUAA.

Share this article
LinkedIn