Authentication Test Process¶
Step-by-step verification for each authentication phase. Run these tests after deploying arc1 to confirm each phase works as intended.
Prerequisites¶
API Key Setup¶
Unit Tests¶
HTTP Profile Manifest Smoke Test¶
When a local HTTP authz test server is already running with four API-key profiles, run:
Default assumptions:
- URL:
http://127.0.0.1:19081/mcp(override withARC1_AUTHZ_MCP_URL) - Keys:
viewer-key-local,sql-key-local,dev-key-local,admin-key-local - Server ceiling: writes, data preview, SQL, and transport writes enabled; Git writes disabled
The script checks the live MCP tools/list manifest for each key. It verifies that unauthorized tools/actions are hidden before any SAP mutation can be attempted:
viewer: noSAPWrite, noSAPQuery, noTABLE_CONTENTS, transport read actions onlyviewer-sql:SAPQueryandTABLE_CONTENTSvisible, no writesdeveloper: writes and transport mutations visible, SQL hidden, Git write actions hiddenadmin: writes, SQL, and transport mutations visible; Git write actions still hidden whenSAP_ALLOW_GIT_WRITES=false
Manual Integration Test¶
1. Start arc1 with API key:
npx arc-1 --url http://your-sap:8000 \
--user DEVELOPER --password secret --client 001 \
--transport http-streamable --http-addr 0.0.0.0:8080 \
--api-keys 'test-key-12345:admin'
2. Verify health endpoint (no auth required):
3. Verify request without API key is rejected:
4. Verify request with wrong API key is rejected:
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer wrong-key" \
http://localhost:8080/mcp
# Expected: 401
5. Verify request with correct API key succeeds:
curl -s -H "Authorization: Bearer test-key-12345" \
-H "Content-Type: application/json" \
http://localhost:8080/mcp \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# Expected: 200 with JSON-RPC response containing tool list
6. Verify case-insensitive Bearer prefix:
curl -s -H "Authorization: bearer test-key-12345" \
-H "Content-Type: application/json" \
http://localhost:8080/mcp \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# Expected: 200 (same as above)
Checklist¶
- [ ] Health endpoint returns 200 without auth
- [ ] Missing Authorization header → 401
- [ ] Wrong API key → 401
- [ ] Correct API key → 200 with tools
- [ ] Case-insensitive "Bearer" prefix works
- [ ] MCP client (VS Code/Cursor) connects with Authorization header
OAuth / JWT Setup¶
Unit Tests¶
Manual Integration Test¶
Prerequisites: You need an OIDC Identity Provider (EntraID, Keycloak, Cognito).
1. Start arc1 with OIDC:
npx arc-1 --url http://your-sap:8000 \
--user DEVELOPER --password secret --client 001 \
--transport http-streamable --http-addr 0.0.0.0:8080 \
--oidc-issuer 'https://your-idp.example.com' \
--oidc-audience 'your-audience'
2. Verify Protected Resource Metadata endpoint:
curl -s http://localhost:8080/.well-known/oauth-protected-resource | jq .
# Expected: JSON with "resource", "authorization_servers", "bearer_methods_supported"
3. Verify request without token is rejected:
4. Get a real JWT from your IdP:
# Example for Azure CLI:
TOKEN=$(az account get-access-token --resource your-audience --query accessToken -o tsv)
# Example for Keycloak (password grant for testing):
TOKEN=$(curl -s -X POST https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token \
-d "grant_type=password&client_id=arc1&username=testuser&password=testpass" | jq -r .access_token)
5. Verify request with valid JWT succeeds:
curl -s -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
http://localhost:8080/mcp \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# Expected: 200 with tool list
6. Verify expired/invalid token is rejected:
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer invalid.jwt.token" \
http://localhost:8080/mcp
# Expected: 401
7. Check logs for username extraction:
Checklist¶
- [ ] Protected Resource Metadata endpoint returns valid JSON
- [ ] Missing token → 401
- [ ] Invalid/expired token → 401
- [ ] Valid JWT → 200 with tools
- [ ] Username extracted from JWT claims (check logs)
- [ ] JWKS auto-discovery works (check logs for JWKS fetch)
Principal Propagation Setup¶
Unit Tests¶
Manual Integration Test¶
Prerequisites: - Phase 2 (OIDC or XSUAA) configured and working - ARC-1 deployed on BTP CF with Destination + Connectivity services - Cloud Connector connected and configured for principal propagation - SAP system configured with CERTRULE / VUSREXTID (see Principal Propagation Setup)
1. Configure ARC-1 with PP:
2. Verify per-user identity in SAP:
Check in SAP transaction SM20 (security audit log) or SM04 (user sessions) that the request was executed as the mapped SAP user, not a technical account.
3. Check ARC-1 logs:
Checklist¶
- [ ] BTP Destination with
PrincipalPropagationauthentication type configured - [ ] Cloud Connector principal propagation enabled
- [ ] SAP certificate mapping (CERTRULE / VUSREXTID) configured
- [ ] JWT-authenticated requests use per-user destination
- [ ] SAP logs show per-user identity (not technical account)
- [ ] Fallback behavior matches
SAP_PP_STRICTsetting
Phase 4: BTP / Cloud Foundry¶
Unit Tests¶
Manual Integration Test¶
To test on BTP Cloud Foundry:
1. Deploy to CF:
2. Verify app is running (check app logs):
cf logs arc1 --recent | grep "BTP"
# Expected: Log messages showing parsed XSUAA and Destination bindings
3. Verify health:
Checklist¶
- [ ] BTP config → OAuth config conversion works
- [ ] App starts on CF without errors
- [ ] Health endpoint returns 200
Full Regression Suite¶
Run all tests:
Quick Smoke Test¶
For a quick check that nothing is broken after code changes: