Skip to content

fix(sdk): use bearer auth for non-dpop Connect tokens - #3806

Merged
strantalis merged 4 commits into
mainfrom
codex/fix-connect-bearer-auth
Jul 31, 2026
Merged

fix(sdk): use bearer auth for non-dpop Connect tokens#3806
strantalis merged 4 commits into
mainfrom
codex/fix-connect-bearer-auth

Conversation

@strantalis

@strantalis strantalis commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

Use the OAuth token response's token_type to select Connect authentication:

  • Send Authorization: Bearer and no DPoP proof for non-DPoP tokens.
  • Preserve Authorization: DPoP and proof generation for DPoP-bound tokens.
  • Preserve existing behavior for custom token sources that do not expose token-binding capability.

Why

The Connect interceptor unconditionally labeled every access token as DPoP. SaaS Audit uses a Bearer token contract and JSON Connect encoding, so its requests were rejected even when the token flow returned a Bearer token.

RFC 9449 makes token_type the authoritative signal for whether the issued token is DPoP-bound. Authorization-server discovery can advertise DPoP support, but does not establish the binding of an individual issued token.

Validation

  • make fmt
  • go test ./... in sdk
  • go test ./... -race in sdk
  • golangci-lint run --new-from-rev=HEAD ./... in sdk

make lint is blocked before code lint by an invalid local Buf API token. Root make test is blocked in lib/fixtures because Keycloak is unavailable at localhost:8888; the SDK race suite passed independently.

Summary by CodeRabbit

  • New Features

    • Added support for identifying Bearer and DPoP access-token schemes.
    • Connect requests now apply the appropriate authorization scheme based on the token type.
    • Access-token retrieval now returns both the token and its authentication scheme.
    • Existing DPoP behavior remains supported for compatible token sources.
  • Bug Fixes

    • Prevented unnecessary DPoP generation for Bearer-authenticated requests.
    • Improved consistency when credentials are refreshed or reused.
  • Tests

    • Added coverage for Bearer, DPoP, token refresh, and concurrent credential scenarios.

Signed-off-by: strantalis <strantalis@virtru.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@strantalis, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 reviews.

How do review 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 refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 51d929cc-9226-4dda-bbf4-5757638ad6f3

📥 Commits

Reviewing files that changed from the base of the PR and between d5641b1 and 66a1010.

📒 Files selected for processing (3)
  • sdk/auth/access_token_source.go
  • sdk/auth/access_token_source_test.go
  • sdk/auth/token_adding_interceptor_test.go
📝 Walkthrough

Walkthrough

The SDK adds atomic access-token credentials that include both the token and its authentication scheme. Token sources return Bearer or DPoP credentials. Connect uses the scheme to select authorization and DPoP generation.

Changes

Credential scheme flow

Layer / File(s) Summary
Credential contracts
sdk/auth/access_token_source.go, sdk/auth/access_token_source_test.go
Defines TokenType, Bearer and DPoP constants, token-type conversion, AccessTokenCredential, and AccessTokenCredentialSource.
Token source credential retrieval
sdk/idp_access_token_source.go, sdk/idp_cert_exchange.go, sdk/idp_oauth_access_token_source.go, sdk/idp_token_exchange_token_source.go, sdk/idp_oauth_access_token_source_test.go
Adds atomic credential retrieval while preserving token caching, refresh behavior, and error handling. Tests cover DPoP and Bearer credentials.
Connect authentication selection
sdk/auth/token_adding_interceptor.go, sdk/auth/token_adding_interceptor_test.go
Uses the credential scheme for authorization. DPoP credentials generate DPoP material. Bearer credentials skip DPoP generation. Tests cover credential refreshes and scheme changes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: dmihalcik-virtru

Poem

A rabbit carries tokens two,
One Bearer bright, one DPoP blue.
The source returns both as one,
Connect chooses what must be done.
Tests hop where headers grew.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: using Bearer authentication for non-DPoP Connect tokens.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-connect-bearer-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size/s comp:sdk A software development kit, including library, for client applications and inter-service communicati labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 221.263071ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 122.316524ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 416.248341ms
Throughput 240.24 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 52.563515154s
Average Latency 523.687868ms
Throughput 95.12 requests/second

@strantalis strantalis changed the title [codex] fix(sdk): use bearer auth for non-dpop Connect tokens fix(sdk): use bearer auth for non-dpop Connect tokens Jul 30, 2026
@strantalis
strantalis marked this pull request as ready for review July 30, 2026 19:36
@strantalis
strantalis requested review from a team as code owners July 30, 2026 19:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@sdk/auth/token_adding_interceptor.go`:
- Around line 103-106: Update the token-selection flow in the interceptor to
obtain the access token and its DPoP/Bearer binding metadata through one atomic
credential-selection operation, rather than calling AccessToken() and
DPoPSupported() separately. Use that returned metadata to select the
Authorization scheme for the exact token, and add a concurrent-refresh
regression test covering both mismatched-binding cases.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 48a890e5-94d0-476e-8986-02187b92f80e

📥 Commits

Reviewing files that changed from the base of the PR and between 8ce0e17 and 355e805.

📒 Files selected for processing (7)
  • sdk/auth/access_token_source.go
  • sdk/auth/token_adding_interceptor.go
  • sdk/auth/token_adding_interceptor_test.go
  • sdk/idp_access_token_source.go
  • sdk/idp_cert_exchange.go
  • sdk/idp_oauth_access_token_source.go
  • sdk/idp_oauth_access_token_source_test.go

Comment thread sdk/auth/token_adding_interceptor.go Outdated
Address CodeRabbit's concurrent token-refresh finding by returning each access token with its DPoP status atomically.

Signed-off-by: strantalis <strantalis@virtru.com>
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 153.817761ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 87.247942ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 410.144087ms
Throughput 243.82 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 47.978440853s
Average Latency 477.854211ms
Throughput 104.21 requests/second

alkalescent
alkalescent previously approved these changes Jul 30, 2026
Comment thread sdk/auth/access_token_source.go Outdated

@dmihalcik-virtru dmihalcik-virtru left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One optional (but large, maybe not worth it) change suggested

Signed-off-by: strantalis <strantalis@virtru.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@sdk/auth/access_token_source.go`:
- Around line 22-28: Normalize the OAuth token type comparison in
TokenTypeFromOAuthTokenType by using strings.EqualFold so any casing of DPoP
maps to TokenTypeDPoP; update sdk/auth/access_token_source.go lines 22-28.
Adjust the lowercase dpop test expectation in
sdk/auth/access_token_source_test.go lines 11-14 to expect TokenTypeDPoP.

In `@sdk/auth/token_adding_interceptor_test.go`:
- Around line 305-319: Update ConcurrentRefreshTokenSource so its
credential-fetch behavior is stateful: return credential on the first
AccessTokenCredential call and refreshed on the second, using suitable
synchronization if needed for concurrent access. Ensure the existing “when
refresh returns bearer” and “when refresh returns dpop” cases exercise the
refreshed credential and consume the refreshed field, while preserving the
initial credential behavior.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bca82a10-c252-48b8-b2aa-5260188d1078

📥 Commits

Reviewing files that changed from the base of the PR and between 355e805 and d5641b1.

📒 Files selected for processing (9)
  • sdk/auth/access_token_source.go
  • sdk/auth/access_token_source_test.go
  • sdk/auth/token_adding_interceptor.go
  • sdk/auth/token_adding_interceptor_test.go
  • sdk/idp_access_token_source.go
  • sdk/idp_cert_exchange.go
  • sdk/idp_oauth_access_token_source.go
  • sdk/idp_oauth_access_token_source_test.go
  • sdk/idp_token_exchange_token_source.go

Comment thread sdk/auth/access_token_source.go
Comment thread sdk/auth/token_adding_interceptor_test.go Outdated
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 210.734884ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 105.934084ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 684.737658ms
Throughput 146.04 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 49.647676485s
Average Latency 494.68992ms
Throughput 100.71 requests/second

Signed-off-by: strantalis <strantalis@virtru.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 201.980176ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 134.613715ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 417.672773ms
Throughput 239.42 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 49.352888139s
Average Latency 491.655385ms
Throughput 101.31 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • examples
  • otdfctl
  • sdk
  • service
  • lib/fixtures
  • tests-bdd

See the workflow run for details.

@dmihalcik-virtru dmihalcik-virtru left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 small optional change

Comment thread sdk/auth/token_adding_interceptor.go
@strantalis
strantalis enabled auto-merge July 31, 2026 18:40
@strantalis
strantalis added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit 4e140ac Jul 31, 2026
45 checks passed
@strantalis
strantalis deleted the codex/fix-connect-bearer-auth branch July 31, 2026 19:00
khvirtru pushed a commit to khvirtru/platform that referenced this pull request Aug 5, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.28.0](opentdf/platform@sdk/v0.27.0...sdk/v0.28.0)
(2026-08-03)


### Features

* **sdk:** add AccessToken accessor to SDK
([opentdf#3775](opentdf#3775))
([2911e22](opentdf@2911e22))


### Bug Fixes

* **sdk:** use bearer auth for non-dpop Connect tokens
([opentdf#3806](opentdf#3806))
([4e140ac](opentdf@4e140ac))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:sdk A software development kit, including library, for client applications and inter-service communicati size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants