DEV-1602: re-enable Claude.ai subscription (OAuth) auth for the Claude Agent SDK - #59
Conversation
…e Agent SDK DEV-1579 severed the OAuth path ONLY at the agents/claude_sdk/sdk_env.py choke point (the cloud --subscription-auth plumbing stayed intact). Anthropic confirmed OAuth was never actually disabled upstream, so re-enable it. Path is chosen by an EXPLICIT operator signal (BIRD_INTERACT_SUBSCRIPTION_AUTH), never inferred from which credential survives. Registry/open-weight exemption is checked FIRST, so the Anthropic-only signal is inert for registry models. - sdk_env.py: `_subscription_auth_selected()` reads the signal var. `assert_api_key_auth` accepts a valid sk-ant-oat01- CLAUDE_CODE_OAUTH_TOKEN on the subscription path (missing/malformed hard-fails, no fall-back to the API key); else requires ANTHROPIC_API_KEY. `build_hermetic_session_env` masks ANTHROPIC_API_KEY in the subprocess options.env on the subscription path (precedence trap) and lets the OAuth token inherit; API-key path keeps masking the OAuth token. Registry layering unchanged (masks both, wins). - cloud/driver.py + cloud/prereqs.py: gate the OAuth branch on the agent model NOT being a registry model (registry-first); the driver ships BIRD_INTERACT_SUBSCRIPTION_AUTH=1 to the actors on the OAuth path. - run.py: new --subscription-auth flag (default off) + `_apply_subscription_auth_env` helper that sets/clears the signal var locally; Anthropic-only, claude_sdk-only. - Credential forwarding stays env-var only (no .credentials.json copy), so the DEV-1579 hermetic CLAUDE_CONFIG_DIR isolation + MCP parity are preserved. - Supersedes DEV-1582 (retire --subscription-auth machinery). Docstrings + CLAUDE.md updated to drop the "OAuth is dead" wording. Tests: rewritten/added across tests/test_sdk_subprocess_hermetic.py, tests/cloud/test_driver.py, tests/cloud/test_prereqs.py, the new tests/test_dev1602_run_subscription_flag.py, and an OAuth-path real-CLI smoke in tests/test_dev1579_hermetic_integration.py (@pytest.mark.integration). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DEV-1602 Re-enable Claude.ai subscription (OAuth) auth for the Claude Agent SDK
ContextDEV-1579 (2026-06-15) disabled Claude.ai subscription / OAuth auth ( Effect: a cloud submit with GoalRe-enable the subscription/OAuth path so cloud opus Scope / investigation
AcceptanceA cloud opus Tests
Why nowBlocks running opus cloud smokes on the subscription — e.g. validating the DEV-1589 claude_sdk OTF encoder branch end-to-end — without burning API credits. Once this lands, the DEV-1589 branch will be merged with it and the deferred single-DB opus smoke launched. |
|
Warning Review limit reached
More reviews will be available in 48 minutes and 50 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds a ChangesSubscription/OAuth Auth Path for claude_sdk Agents
Sequence Diagram(s)sequenceDiagram
participant Operator
participant run.py
participant provider_registry
participant cloud_driver
participant cloud_prereqs
participant sdk_env
participant ClaudeSDK
Operator->>run.py: parse --subscription-auth
run.py->>provider_registry: get_provider(agent_model)
provider_registry-->>run.py: registry or none
run.py->>run.py: set or clear BIRD_INTERACT_SUBSCRIPTION_AUTH
Operator->>cloud_driver: read_api_keys_from_local_env
cloud_driver->>provider_registry: get_provider(agent_model)
provider_registry-->>cloud_driver: registry or none
cloud_driver->>cloud_driver: return env with token and signal when enabled
Operator->>cloud_prereqs: check_api_keys
cloud_prereqs->>provider_registry: get_provider(agent_model)
provider_registry-->>cloud_prereqs: registry or none
cloud_prereqs->>cloud_prereqs: require provider key or OAuth token
Operator->>sdk_env: hermetic_claude_sdk_session
sdk_env->>provider_registry: get_provider(agent_model)
provider_registry-->>sdk_env: registry or none
sdk_env->>ClaudeSDK: spawn with masked subprocess env
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/cloud/test_driver.py`:
- Around line 1283-1294: The
test_read_api_keys_api_key_path_no_subscription_signal regression case is too
weak because it deletes CLAUDE_CODE_OAUTH_TOKEN before calling
driver.read_api_keys_from_local_env, so it does not verify that
no_subscription_auth=True suppresses BIRD_INTERACT_SUBSCRIPTION_AUTH even when
an ambient OAuth token exists. Keep the OAuth token set in this test, still set
ANTHROPIC_API_KEY, and assert the returned keys do not include
BIRD_INTERACT_SUBSCRIPTION_AUTH so the explicit opt-out behavior is covered.
In `@tests/test_dev1602_run_subscription_flag.py`:
- Around line 143-147: Strengthen the wiring test for run.main by asserting
actual execution of _apply_subscription_auth_env rather than just searching
run.main source text. Update test_main_invokes_subscription_auth_helper to
invoke main with a controlled setup and verify the helper is called via a
mock/spy or observable side effect, so comments, string literals, or dead
references cannot satisfy the test.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bc49a6fb-14af-4679-96b0-3557ed1f2939
📒 Files selected for processing (10)
CLAUDE.mdsrc/bird_interact_agents/agents/claude_sdk/sdk_env.pysrc/bird_interact_agents/cloud/driver.pysrc/bird_interact_agents/cloud/prereqs.pysrc/bird_interact_agents/run.pytests/cloud/test_driver.pytests/cloud/test_prereqs.pytests/test_dev1579_hermetic_integration.pytests/test_dev1602_run_subscription_flag.pytests/test_sdk_subprocess_hermetic.py
- sdk_env.build_hermetic_session_env: on the subscription path mask ANTHROPIC_AUTH_TOKEN too (not just ANTHROPIC_API_KEY) — it is an SDK Bearer credential the auth-precedence rule would otherwise pick over the OAuth token (Codex). OAuth stays authoritative; no silent fallback. - driver.read_api_keys_from_local_env + prereqs.check_api_keys: scope the registry-first exemption to PROVIDER-AWARE claude_sdk* frameworks so the Anthropic-only `annotator` (provider_aware=False) never diverts to the provider-key branch for a registry agent model — it stays on the OAuth path (Codex). - tests: keep an ambient OAuth token in the API-key-path driver test so the explicit opt-out is proven to beat ambient creds (CodeRabbit); AST-assert the helper is actually CALLED in run.main, not merely present in source (CodeRabbit); add driver+prereqs annotator-registry-stays-on-OAuth tests and the ANTHROPIC_AUTH_TOKEN mask assertion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arly guard A registry agent model on the `annotator` framework (which runs provider_aware=False, Anthropic-only, at runtime) previously fell through to the generic provider-key branch when --no-subscription-auth was set (annotate has no model-provider validation, unlike submit), shipping a provider key the runtime would reject. Replace the OAuth-branch-only scoping with a single explicit fail-early guard in both read_api_keys_from_local_env and check_api_keys: the annotator rejects any non-Anthropic agent model up front, consistently for every no_subscription_auth value. The OAuth registry-first gate reverts to its simple `get_provider(agent_model) is None` form. Tests updated: annotator + registry now raises "Anthropic-only" early (parametrized over both subscription-auth values). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-Anthropic models The annotator Anthropic-only guard previously rejected only registry models (get_provider() is not None), so openai/*, gemini/*, etc. — which are not in the open-weight registry — still slipped through to the OAuth/provider-key branches and failed late. Generalise the guard in both read_api_keys_from_local_env and check_api_keys to reject any agent model that isn't anthropic/*. Tests parametrized over both a registry (moonshot/*) and a non-registry (openai/*) non-Anthropic model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The local run.py CLI diverged from the cloud submit CLI on several flags. Align local → cloud (cloud was already the canonical shape): - Make --agent-model, --mode, --query-mode REQUIRED (no defaults) — matches cloud's explicit-choice philosophy (no silent wrong/expensive run). - --subscription-auth: switch local default False → None and mirror cloud's explicit-choice rule — a claude_sdk* run on an Anthropic agent model must pass --subscription-auth or --no-subscription-auth (registry models exempt; non-claude_sdk defaults off). - --patience default 3 → 250 (3 was too low and skewed local eval vs cloud). - --user-sim-model default haiku-4-5 → claude-sonnet-4-6 (cloud default). - --use-audited-gold-sql: store_true/default False → BooleanOptionalAction/ default True (cloud default; pass --no-use-audited-gold-sql to opt out). - (--strict left as-is per request — near-cosmetic.) --dataset was already required on both; verified. Tests: the run-wiring / one-shot / slayer-setup tests that drove run.main with synthesized argv now pass the newly-required --agent-model / --query-mode / --no-subscription-auth; the DEV-1602 flag tests pin the new default=None explicit-choice behavior and the required-flag + value-default contract. README local examples updated to the required-flag surface. Full non-integration suite: 3383 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/bird_interact_agents/run.py (1)
1663-1705: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReject non-Anthropic non-registry models before enabling OAuth.
Line 1664 only distinguishes registry models, so
--subscription-auth --framework claude_sdk --agent-model openai/...passes the OAuth token checks and setsBIRD_INTERACT_SUBSCRIPTION_AUTH=1. That contradicts the Anthropic-only flag contract and can send the downstream SDK down the wrong auth path.Proposed fix
is_claude_sdk = framework.startswith("claude_sdk") is_registry = get_provider(agent_model) is not None + is_anthropic_model = agent_model.startswith("anthropic/") # Explicit-choice requirement (cloud parity): claude_sdk* + Anthropic model # must pass --subscription-auth or --no-subscription-auth. - if is_claude_sdk and not is_registry and subscription_auth is None: + if ( + is_claude_sdk + and is_anthropic_model + and not is_registry + and subscription_auth is None + ): error( "an explicit --subscription-auth / --no-subscription-auth choice is " "required for claude_sdk* runs on an Anthropic agent model (no " "default, to prevent a silent fall-back to the API-key path)." ) @@ if is_registry: error( f"--subscription-auth is Anthropic-only; {agent_model!r} is a " "registry open-weight model that authenticates via its provider " "key. Omit the flag for registry models." ) return + if not is_anthropic_model: + error( + f"--subscription-auth is Anthropic-only; got non-Anthropic " + f"agent_model={agent_model!r}." + ) + return🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/bird_interact_agents/run.py` around lines 1663 - 1705, The subscription-auth gate in the run.py auth setup is only excluding registry models, so claude_sdk runs with non-Anthropic non-registry agent models can still pass and enable BIRD_INTERACT_SUBSCRIPTION_AUTH. Update the validation in the same block around is_claude_sdk, is_registry, and subscription_auth so that only Anthropic models are allowed to proceed; reject any other agent_model before checking CLAUDE_CODE_OAUTH_TOKEN or setting the env var. Keep the existing error path and make the check explicit in the subscription-auth handling logic.src/bird_interact_agents/cloud/prereqs.py (1)
264-275: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMirror the driver fix: don’t treat every non-registry model as Anthropic.
This OAuth prereq branch also matches
openai/...,gemini/..., etc. because those are non-registry. That makes the prereq check requireCLAUDE_CODE_OAUTH_TOKENfor non-Anthropic models instead of rejecting the invalid subscription-auth combination.Proposed fix
+ _agent_spec = provider_registry.get_provider(agent_model) + if ( + _is_claude_sdk_framework(framework) + and not no_subscription_auth + and _agent_spec is None + and not agent_model.startswith("anthropic/") + ): + raise PrereqError( + "--subscription-auth is Anthropic-only; got non-Anthropic " + f"agent model {agent_model!r}.", + remediation=( + "pass an anthropic/* --agent-model for subscription auth, " + "use a registry model provider path, or pass --no-subscription-auth." + ), + ) + if ( _is_claude_sdk_framework(framework) and not no_subscription_auth - and provider_registry.get_provider(agent_model) is None + and _agent_spec is None + and agent_model.startswith("anthropic/") ):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/bird_interact_agents/cloud/prereqs.py` around lines 264 - 275, The OAuth prereq gate in prereqs.py is too broad because it only excludes registry models, so non-Anthropic models like openai/... and gemini/... can incorrectly enter the Claude subscription-auth path. Tighten the condition around the existing `_is_claude_sdk_framework`, `no_subscription_auth`, and `provider_registry.get_provider(agent_model)` checks so the OAuth branch is only reachable for Anthropic-Claude models, mirroring the driver-side guard and rejecting invalid subscription-auth combinations for other providers.src/bird_interact_agents/cloud/driver.py (1)
189-224: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winGate the OAuth branch on an Anthropic agent model, not just “not registry”.
For
framework="claude_sdk"andagent_model="openai/...",provider_registry.get_provider(agent_model) is Noneis true, so this branch requires and forwardsCLAUDE_CODE_OAUTH_TOKEN. That is neither the registry path nor a valid Anthropic subscription-auth target.Proposed fix
- if ( + _agent_spec = provider_registry.get_provider(agent_model) + if ( + _is_claude_sdk_framework(framework) + and not no_subscription_auth + and _agent_spec is None + and not agent_model.startswith("anthropic/") + ): + raise PrereqError( + "--subscription-auth is Anthropic-only; got non-Anthropic " + f"agent model {agent_model!r}.", + remediation=( + "pass an anthropic/* --agent-model for subscription auth, " + "use a registry model provider path, or pass --no-subscription-auth." + ), + ) + + if ( _is_claude_sdk_framework(framework) and not no_subscription_auth - and provider_registry.get_provider(agent_model) is None + and _agent_spec is None + and agent_model.startswith("anthropic/") ):Then reuse
_agent_specfor the registry branch below instead of recomputing it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/bird_interact_agents/cloud/driver.py` around lines 189 - 224, The OAuth path in driver.py is currently gated only by provider_registry.get_provider(agent_model) being None, which incorrectly sends non-Anthropic models like openai/... into the CLAUDE_CODE_OAUTH_TOKEN branch. Update the condition around the claude_sdk subscription-auth logic to require an Anthropic agent model using _agent_spec (and its provider/model metadata) rather than “not registry” alone, so only valid Anthropic subscription-auth targets reach the OAuth checks and token forwarding. Also reuse the existing _agent_spec for the registry/provider branch below instead of recomputing the lookup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Around line 47-49: The updated README examples still invoke bird-interact
directly instead of using the repo’s required uv run prefix. Update the newly
changed command examples in the README so they consistently use uv run
bird-interact (or the equivalent project-tool invocation pattern already used
elsewhere), and apply the same fix to the other bird-interact examples
referenced in this section.
---
Outside diff comments:
In `@src/bird_interact_agents/cloud/driver.py`:
- Around line 189-224: The OAuth path in driver.py is currently gated only by
provider_registry.get_provider(agent_model) being None, which incorrectly sends
non-Anthropic models like openai/... into the CLAUDE_CODE_OAUTH_TOKEN branch.
Update the condition around the claude_sdk subscription-auth logic to require an
Anthropic agent model using _agent_spec (and its provider/model metadata) rather
than “not registry” alone, so only valid Anthropic subscription-auth targets
reach the OAuth checks and token forwarding. Also reuse the existing _agent_spec
for the registry/provider branch below instead of recomputing the lookup.
In `@src/bird_interact_agents/cloud/prereqs.py`:
- Around line 264-275: The OAuth prereq gate in prereqs.py is too broad because
it only excludes registry models, so non-Anthropic models like openai/... and
gemini/... can incorrectly enter the Claude subscription-auth path. Tighten the
condition around the existing `_is_claude_sdk_framework`,
`no_subscription_auth`, and `provider_registry.get_provider(agent_model)` checks
so the OAuth branch is only reachable for Anthropic-Claude models, mirroring the
driver-side guard and rejecting invalid subscription-auth combinations for other
providers.
In `@src/bird_interact_agents/run.py`:
- Around line 1663-1705: The subscription-auth gate in the run.py auth setup is
only excluding registry models, so claude_sdk runs with non-Anthropic
non-registry agent models can still pass and enable
BIRD_INTERACT_SUBSCRIPTION_AUTH. Update the validation in the same block around
is_claude_sdk, is_registry, and subscription_auth so that only Anthropic models
are allowed to proceed; reject any other agent_model before checking
CLAUDE_CODE_OAUTH_TOKEN or setting the env var. Keep the existing error path and
make the check explicit in the subscription-auth handling logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9c2ec475-09ff-4d70-b299-2c5e9f343a1e
📒 Files selected for processing (14)
README.mdsrc/bird_interact_agents/agents/claude_sdk/sdk_env.pysrc/bird_interact_agents/cloud/driver.pysrc/bird_interact_agents/cloud/prereqs.pysrc/bird_interact_agents/run.pytests/cloud/test_driver.pytests/cloud/test_prereqs.pytests/test_claude_sdk_otf_ainteract_v1_run_wiring.pytests/test_claude_sdk_otf_v1_run_wiring.pytests/test_dev1602_run_subscription_flag.pytests/test_one_shot_mode.pytests/test_pydantic_ai_otf_encode_run_wiring.pytests/test_sdk_subprocess_hermetic.pytests/test_slayer_setup_flag.py
✅ Files skipped from review due to trivial changes (2)
- tests/test_claude_sdk_otf_ainteract_v1_run_wiring.py
- tests/test_slayer_setup_flag.py
🚧 Files skipped from review as they are similar to previous changes (2)
- src/bird_interact_agents/agents/claude_sdk/sdk_env.py
- tests/test_sdk_subprocess_hermetic.py
…c-ONLY + README uv run
CodeRabbit (3 majors, same root cause): the --subscription-auth gate was keyed
on "not a registry model" rather than "is an Anthropic model", so a claude_sdk*
run on a non-Anthropic, non-registry model (openai/*, gemini/*) wrongly took the
OAuth path. Fix in all three places:
- run.py _apply_subscription_auth_env: gate on agent_model.startswith("anthropic/")
(is_anthropic) instead of "not is_registry"; the explicit-choice requirement and
the True-path reject now both key off is_anthropic, so non-Anthropic models
(registry or openai/gemini) are rejected with an Anthropic-only message.
- cloud/driver.py + cloud/prereqs.py: add an Anthropic-only reject for a
claude_sdk* subscription run on a non-Anthropic non-registry model, before the
OAuth branch (registry still routes to the provider-key branch).
CodeRabbit (minor): README local examples now use `uv run bird-interact`
consistently (project rule).
Tests added for the non-Anthropic non-registry rejection in run.py / driver /
prereqs. run_evaluation()'s signature defaults are intentionally left unchanged
(no production path uses them; CLI + cloud pass explicit values) per maintainer
decision. Full non-integration suite: 3387 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
DEV-1579 severed the OAuth path only at the
agents/claude_sdk/sdk_env.pychoke point; the cloud--subscription-authplumbing stayed intact. Anthropic confirmed OAuth was never actually disabled upstream, so this re-enables it.The auth path is chosen by an explicit operator signal (
BIRD_INTERACT_SUBSCRIPTION_AUTH), never inferred from which credential survives. The registry/open-weight exemption is checked first, so the Anthropic-only signal is inert for registry models.Changes
sdk_env.py:_subscription_auth_selected()reads the signal var.assert_api_key_authaccepts a validsk-ant-oat01-CLAUDE_CODE_OAUTH_TOKENon the subscription path (missing/malformed hard-fails — no fall-back to the API key); else requiresANTHROPIC_API_KEY.build_hermetic_session_envmasksANTHROPIC_API_KEYin the subprocessoptions.envon the subscription path (precedence trap) and lets the OAuth token inherit; the API-key path keeps masking the OAuth token. Registry layering unchanged (masks both, wins).cloud/driver.py+cloud/prereqs.py: gate the OAuth branch on the agent model not being a registry model (registry-first); the driver shipsBIRD_INTERACT_SUBSCRIPTION_AUTH=1to the actors on the OAuth path.run.py: new--subscription-authflag (default off) +_apply_subscription_auth_envhelper that sets/clears the signal var locally; Anthropic-only, claude_sdk-only..credentials.jsoncopy), so the DEV-1579 hermeticCLAUDE_CONFIG_DIRisolation + MCP parity are preserved.--subscription-authmachinery). Docstrings + CLAUDE.md updated to drop the "OAuth is dead" wording.Tests
Rewritten/added across
tests/test_sdk_subprocess_hermetic.py,tests/cloud/test_driver.py,tests/cloud/test_prereqs.py, the newtests/test_dev1602_run_subscription_flag.py, and an OAuth-path real-CLI smoke intests/test_dev1579_hermetic_integration.py(@pytest.mark.integration). Full non-integration suite: 3370 passed, 94 skipped.Acceptance (manual, follow-up)
Cloud opus
claude_sdksmoke (single DB,--mode a-interact,--subscription-auth) authenticating via the subscription with noANTHROPIC_API_KEYconsumed.🤖 Generated with Claude Code
Summary by CodeRabbit
--subscription-auth/--no-subscription-auth.