github.com/anthropics/anthropic-sdk-go@v1.70.1/config/oautherr.go (about) 1 package config 2 3 import "encoding/json" 4 5 // OAuthErrorBodyMaxLen caps the error body length embedded in OAuth-endpoint 6 // failure error messages. Token-endpoint responses are untrusted and are 7 // routinely captured in logs; the cap covers identity-provider proxies that 8 // concatenate upstream messages into error_description. 9 const OAuthErrorBodyMaxLen = 2000 10 11 // oauthErrorAllowedKeys is the RFC 6749 §5.2 allowlist surfaced in 12 // user-facing errors. Any other key is dropped — providers have been seen 13 // to echo back the assertion JWT or a partially-minted token, neither of 14 // which may appear in logs. error_description is attacker-controllable 15 // free-form text; callers must treat redacted output as untrusted. 16 var oauthErrorAllowedKeys = []string{ 17 "error", 18 "error_description", 19 "error_uri", 20 } 21 22 // RedactOAuthErrorBody returns a safe-to-log form of an OAuth token endpoint 23 // failure body. If the body parses as a JSON object, only the RFC 6749 §5.2 24 // allowed keys are kept. Non-JSON bodies are replaced with a redaction 25 // placeholder. Either way the result is truncated to [OAuthErrorBodyMaxLen]. 26 func RedactOAuthErrorBody(body string) string { 27 var obj map[string]any 28 // err only — Unmarshal("null") sets obj=nil with no error; nil filters to {}. 29 if err := json.Unmarshal([]byte(body), &obj); err == nil { 30 filtered := make(map[string]any, len(oauthErrorAllowedKeys)) 31 for _, k := range oauthErrorAllowedKeys { 32 if v, present := obj[k]; present { 33 filtered[k] = v 34 } 35 } 36 if b, err := json.Marshal(filtered); err == nil { 37 body = string(b) 38 } 39 } else { 40 body = "[redacted; not a JSON error response]" 41 } 42 if len(body) > OAuthErrorBodyMaxLen { 43 body = body[:OAuthErrorBodyMaxLen] + "...[truncated]" 44 } 45 return body 46 }