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 — 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. Add a manual refresh:

@dm.retry(max_attempts=3, on=(AuthError,))
def push_batch(rows):
sap.post(entity="A_BusinessPartner", rows=rows)

The retry triggers a fresh token fetch.

Bearer / API key shows up in logs

By default DataMaker redacts Authorization headers in audit logs and live console output. If you’re seeing tokens in your own scenario print() statements, that’s on you — switch to dm.log.info(...) which redacts on Authorization and on field names marked sensitive.

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