feat(auth): support cloak config in OAuth credential JSON files#2709
feat(auth): support cloak config in OAuth credential JSON files#2709nyakojiru wants to merge 1 commit intorouter-for-me:devfrom
Conversation
The cloak configuration (mode, strict-mode, sensitive-words, cache-user-id)
was only supported for claude-api-key entries in config.yaml. OAuth
credentials from --claude-login had no way to control cloaking behavior,
forcing all OAuth requests to use the default "auto" mode which injects
the Claude Code system prompt.
This change extracts cloak configuration from the "cloak" object in OAuth
auth JSON files and populates the corresponding auth attributes so that
getCloakConfigFromAuth can read them at runtime.
Usage: Add a "cloak" field to the OAuth credential JSON file:
{"cloak": {"mode": "never"}}
Supported fields mirror the claude-api-key cloak config:
- mode: "auto" (default), "always", or "never"
- strict-mode: boolean
- sensitive-words: array of strings
- cache-user-id: boolean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
This pull request targeted The base branch has been automatically changed to |
There was a problem hiding this comment.
Code Review
This pull request implements the extraction of cloak configuration from auth file metadata into attributes in both the synthesizer and the SDK's file token store. The reviewer recommends refactoring this duplicated logic into a shared utility function to improve maintainability and suggests using string trimming for more robust configuration parsing.
| // Extract cloak configuration from auth file metadata into attributes | ||
| // so that getCloakConfigFromAuth can read them for OAuth credentials. | ||
| if cloakObj, ok := metadata["cloak"].(map[string]any); ok { | ||
| if mode, ok := cloakObj["mode"].(string); ok && mode != "" { | ||
| a.Attributes["cloak_mode"] = mode | ||
| } | ||
| if strict, ok := cloakObj["strict-mode"].(bool); ok && strict { | ||
| a.Attributes["cloak_strict_mode"] = "true" | ||
| } | ||
| if words, ok := cloakObj["sensitive-words"].([]any); ok && len(words) > 0 { | ||
| var parts []string | ||
| for _, w := range words { | ||
| if s, ok := w.(string); ok { | ||
| parts = append(parts, s) | ||
| } | ||
| } | ||
| if len(parts) > 0 { | ||
| a.Attributes["cloak_sensitive_words"] = strings.Join(parts, ",") | ||
| } | ||
| } | ||
| if cache, ok := cloakObj["cache-user-id"].(bool); ok && cache { | ||
| a.Attributes["cloak_cache_user_id"] = "true" | ||
| } | ||
| } |
There was a problem hiding this comment.
The logic for extracting cloak configuration from metadata is duplicated here and in sdk/auth/filestore.go. To improve maintainability and ensure consistency, consider refactoring this into a shared utility function within the sdk/cliproxy/auth package (e.g., ApplyCloakConfigFromMetadata), similar to how ApplyCustomHeadersFromMetadata is implemented. This would ensure that any future changes to the cloak configuration schema are applied consistently across both the runtime and SDK paths.
Additionally, consider using strings.TrimSpace when parsing the mode and sensitive-words to make the configuration more robust, consistent with how other fields like prefix or note are handled in this file.
| // Extract cloak configuration from auth file metadata into attributes | ||
| // so that getCloakConfigFromAuth can read them for OAuth credentials. | ||
| if cloakObj, ok := metadata["cloak"].(map[string]any); ok { | ||
| if mode, ok := cloakObj["mode"].(string); ok && mode != "" { | ||
| auth.Attributes["cloak_mode"] = mode | ||
| } | ||
| if strict, ok := cloakObj["strict-mode"].(bool); ok && strict { | ||
| auth.Attributes["cloak_strict_mode"] = "true" | ||
| } | ||
| if words, ok := cloakObj["sensitive-words"].([]any); ok && len(words) > 0 { | ||
| var parts []string | ||
| for _, w := range words { | ||
| if s, ok := w.(string); ok { | ||
| parts = append(parts, s) | ||
| } | ||
| } | ||
| if len(parts) > 0 { | ||
| auth.Attributes["cloak_sensitive_words"] = strings.Join(parts, ",") | ||
| } | ||
| } | ||
| if cache, ok := cloakObj["cache-user-id"].(bool); ok && cache { | ||
| auth.Attributes["cloak_cache_user_id"] = "true" | ||
| } | ||
| } |
There was a problem hiding this comment.
luispater
left a comment
There was a problem hiding this comment.
Summary:
This change moves OAuth cloak metadata into auth attributes so getCloakConfigFromAuth() can consume it, which is the right integration point.
Blocking findings:
- The same auth-file parsing logic still exists in the Git/Object/Postgres stores, and those paths do not populate
cloak_mode,cloak_strict_mode,cloak_sensitive_words, orcloak_cache_user_id. As written, the feature only works for the file watcher / SDK filestore paths and stays broken for the supported alternative auth backends. buildAuthFromFileData()in the management auth-file handler still drops the newcloakmetadata before upserting the auth into the manager, so files uploaded or updated through the management API will not honor the new settings immediately.
Non-blocking:
- Please add focused regression tests for the watcher and SDK auth-file loaders so this mapping is covered explicitly.
Recommendation:
Please move the cloak extraction into a shared helper and reuse it across every auth JSON ingestion path before merging.
Summary
cloakconfiguration from OAuth credential JSON files (created via--claude-login)cloak.modewas only configurable forclaude-api-keyentries inconfig.yaml— OAuth credentials always used the default"auto"mode, injecting the Claude Code system prompt into every requestcloakobject from auth file metadata and populates auth attributes (cloak_mode,cloak_strict_mode,cloak_sensitive_words,cloak_cache_user_id) so thatgetCloakConfigFromAuth()can read them at runtimeUsage
Add a
"cloak"field to the OAuth credential JSON file in the auth directory:{ "type": "claude", "email": "user@example.com", "cloak": { "mode": "never" } }Supported fields mirror the
claude-api-keycloak config:mode:"auto"(default),"always", or"never"strict-mode: booleansensitive-words: array of stringscache-user-id: booleanProblem
When using OAuth credentials (
--claude-login), downstream applications sending their own system prompts had the Claude Code system prompt (~1,378 tokens) prepended to every request. This caused:Changes
internal/watcher/synthesizer/file.go: Extract cloak config from metadata during auth synthesis (runtime code path)sdk/auth/filestore.go: Extract cloak config from metadata during file reading (SDK code path)Test plan
cloak_modeattribute is populated from auth JSON file on startupcloak.mode: "never"— prompt tokens dropped from ~1,477 to 23 (clean passthrough)🤖 Generated with Claude Code