Skip to content

CSRF & auth

If you’ve worked with SAP OData before, CSRF is the #1 source of confusion. This page walks through DataMaker’s behaviour and the most common failure modes.

How DataMaker handles CSRF (the happy path)

For SAP OData V2 and V4, modifying requests need a CSRF token. The flow:

1. GET /service/ → 200 OK
X-CSRF-Token: Fetch X-CSRF-Token: <token-A>
sap-cookie: <session> sap-cookie: <session>
2. POST /service/Entity → 201 Created
X-CSRF-Token: <token-A> (token-A is consumed but stays valid
sap-cookie: <session> for the same session)
3. POST /service/Entity → 201 Created (re-uses token-A)
4. Session expires...
POST /service/Entity → 403 CSRF validation failed
5. DataMaker auto-fetches new token, retries:
GET /service/ → X-CSRF-Token: <token-B>
POST /service/Entity → 201 Created

DataMaker handles steps 1 and 5 transparently. You never set X-CSRF-Token yourself.

Failure: 403 CSRF token validation failed (persistent)

If retries don’t help, the token isn’t being recognised. Causes:

  • Auth backend changes the session per request. Some OAuth2 flows mint a fresh token per call; the CSRF token from request N is valid for session N, not N+1. Switch to BasicAuth or a long-lived bearer.

  • Cookie jar reset. If the connection is going through a proxy that strips cookies, the SAP backend treats every request as a new session. Configure the proxy to forward sap-* cookies.

  • Wrong endpoint for fetch. Some custom services don’t return a token from the service root. Override the fetch endpoint:

    {
    "auth": { "type": "basic", ... },
    "csrf": { "fetch_path": "/some/other/path", "fetch_method": "HEAD" }
    }

Failure: 401 on GET $metadata but 200 on regular GET

Your auth works for data but not for metadata. Some SAP gateways apply different rules to $metadata (especially in SAP Cloud Connector setups). Two fixes:

  • Configure the gateway to allow $metadata for the same auth.
  • Provide a manually-uploaded metadata document via Connection → Metadata → Upload. DataMaker uses the uploaded $metadata and doesn’t fetch it at runtime.

OAuth2 client credentials: invalid_client

The token endpoint rejected your client_id / client_secret. Walk the chain:

  • Curl the token endpoint with the same credentials and verify you get a token back.
  • Check Content-Type: application/x-www-form-urlencoded (not application/json). Some IdPs are picky.
  • For Azure AD, the scope parameter is required and most often is <resource>/.default.

OAuth2 token expired mid-scenario

DataMaker caches tokens until 60 seconds before their stated expires_in. If your scenario runs longer than that, tokens are refreshed transparently.

If you’re seeing 401 on a long run, the IdP’s expires_in is likely lying. Some servers say “3600s” but rotate at ~30 minutes. Wrap the push in a retry so each attempt re-fetches a fresh token:

def with_reauth(call, attempts=3):
for i in range(attempts):
try:
return call()
except Exception:
if i == attempts - 1:
raise
# the next attempt triggers a fresh token fetch

Bearer / API key shows up in logs

DataMaker doesn’t print your auth headers, but if you print() a request or response that contains a token, it lands in the run log. Don’t print secrets: log a status code or a redacted summary instead.

Two-factor / interactive auth

DataMaker doesn’t run interactive auth flows (no browser, no TOTP prompts). If your target system requires interactive auth, you have two options:

  • Use the platform’s machine-to-machine auth (service accounts, client credentials).
  • Manually obtain a long-lived token outside DataMaker and store it as a workspace secret. Refresh it on a schedule.

See also