[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client - #3432

Draft
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909
Draft

[IDENTITY-7909] Scope logout revocation to the CLI Auth0 client#3432
Matt Carle (mcarle) wants to merge 1 commit into
mainfrom
mcarle/IDENTITY-7909

Conversation

@mcarle

@mcarleMatt Carle (mcarle) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Release Notes

Bug Fixes

  • confluent logout now revokes only the CLI's own Confluent Cloud session. It previously revoked every Auth0 refresh token for the account, which signed the user out of the web UI and other clients as well.

Checklist

  • I have successfully built and used a custom CLI binary, without linter issues from this PR.
  • I have clearly specified in the What section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.
  • I have verified this PR in Confluent Cloud pre-prod or production environment, if applicable.
  • I have verified this PR in Confluent Platform on-premises environment, if applicable.
  • I have attached manual CLI verification results or screenshots in the Test & Review section below.
  • I have added appropriate CLI integration or unit tests for any new or updated commands and functionality.
  • I confirm that this PR introduces no breaking changes or backward compatibility issues.
  • I have indicated the potential customer impact if something goes wrong in the Blast Radius section below.
  • I have put checkmarks below confirming that the feature associated with this PR is enabled in:
    • Confluent Cloud prod
    • Confluent Cloud stag
    • Confluent Platform
    • Check this box if the feature is enabled for certain organizations only

This PR must not merge until cc-flow-service#3440 is deployed to prod. See References.

What

Confluent Cloud only; Confluent Platform and gov (Okta) logout are untouched.

confluent logout called DELETE /api/sessions, which revokes every rotating refresh token belonging to the user's email across all Auth0 clients. Logging out of a terminal therefore also tore down the user's browser session and any IDE-plugin sessions.

DELETE /iam/v2/sessions scopes revocation to a single Auth0 client when given a client ID. This switches the Auth0 logout path to that endpoint, passing the CLI's own client ID — the same value already sent to cc-flow-service at login in pkg/auth/auth_token_handler.go. The session JWT rides along as a bearer token via the existing OAuth2 transport on c.Client.HttpClient, so no new auth plumbing is involved.

Two deliberate behaviour changes beyond the endpoint swap:

Revocation failures no longer abort logout. Previously a transport error returned before local credentials were cleared, leaving the user logged in locally with no way to log out offline. The v1 SDK also swallowed non-200 responses entirely, so server-side failures were invisible. Now local credentials are always cleared, and a failure is both logged and printed to stderr — the user is told their remote session may still be active. Exit code stays 0 so scripted logout calls don't start failing on a transient error.

Any 2xx counts as success. The endpoint returns 200 today; accepting the range avoids a false failure if it ever returns 204.

The request is hand-rolled rather than routed through an SDK. ccloud-sdk-go-v1-public has no v2 sessions method, and the generated SessionsV2Api in ccloud-sdk-go-v2-internal only exposes CreateV2Session (POST) — there is no generated DELETE, and that module isn't currently a dependency of the CLI. Happy to move this into ccloud-sdk-go-v1-public as a LogoutV2 method if reviewers would rather keep all session calls behind Client.Auth; it just costs an extra repo and release.

Blast Radius

Confluent Cloud users running confluent logout. If the new endpoint misbehaves, logout still completes locally — credentials are removed and the user sees a warning — but the Auth0 session and refresh tokens may survive until they expire on their own (30 minutes for refresh tokens, up to 8 hours for the Auth0 session). The failure mode is a session that outlives the logout, not a user who cannot log out.

Gov/FedRAMP users are unaffected: sso.IsOkta still routes them to DELETE /api/okta/auth/sessions, and the upstream revocation RPCs reject FedRAMP calls regardless.

If this ships before cc-flow-service#3440 reaches prod, the client_id parameter is ignored and revocation silently falls back to the old unscoped behaviour — no error, but no improvement either. That is the reason for the merge gate above.

References

Test & Review

Unit tests in internal/logout/command_test.go cover the request shape (method, path, client_id), a 204 response, and a non-2xx response surfacing an error.

go test ./internal/logout/
--- PASS: TestLogout
--- PASS: TestDeleteSession
--- PASS: TestDeleteSessionNoContent
--- PASS: TestDeleteSessionError
ok github.com/confluentinc/cli/v4/internal/logout

The test server gained a /api/iam/v2/sessions route asserting the method and a non-empty client_id, so the existing logout integration tests now exercise the new path end to end. I confirmed the route is genuinely reached by temporarily failing inside the handler and watching the suite fail — worth noting because a handler that is never called would otherwise pass silently.

make integration-test INTEGRATION_TEST_ARGS="-run 'TestCLI/(TestLogout|TestLogin)'"
--- PASS: TestCLI (11.97s)

Not yet verified against a deployed environment — that needs cc-flow-service#3440 in devel first, and I'll do that before marking this ready for review.

Two pre-existing failures in my local environment, both reproduced on an unmodified main checkout and unrelated to this change:

  • pkg/flink/internal/controller panics with open /dev/tty: device not configured (needs a real TTY).
  • make lint-go fails with can't load config: unsupported version of the configuration (local golangci-lint version vs .golangci.yml). go vet ./... is clean.

DELETE /api/sessions revokes every rotating refresh token for the user,
so logging out of the terminal also tore down the browser session.
Call DELETE /api/iam/v2/sessions with the CLI client_id instead, which
scopes revocation to the CLI. Gov environments keep the Okta path.
Revocation failures no longer abort logout; local credentials are
cleared either way and the failure is reported on stderr.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@confluent-cla-assistant

Copy link
Copy Markdown

🎉 All Contributor License Agreements have been signed. Ready to merge.
Please push an empty commit if you would like to re-run the checks to verify CLA status for all contributors.

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

Pull request overview

Updates confluent logout (Confluent Cloud only) to revoke sessions via the IAM v2 sessions endpoint with an explicit Auth0 client_id, so logout only revokes the CLI’s own session rather than all refresh tokens for the account.

Changes:

  • Switches cloud logout revocation from the v1 /api/sessions path to DELETE /api/iam/v2/sessions?client_id=....
  • Makes remote revocation best-effort (warnings on failure) while always clearing local credentials.
  • Extends unit + integration test coverage by adding a new mocked route/handler and direct request-shape tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

FileDescription
internal/logout/command.goImplements the new DELETE /api/iam/v2/sessions revocation flow and makes revocation failures non-fatal to local logout.
internal/logout/command_test.goAdds unit tests for the new delete-session request shape and status-code handling.
test/test-server/ccloud_router.goRegisters the new /api/iam/v2/sessions route in the integration-test server router.
test/test-server/ccloud_handlers.goAdds a handler asserting the DELETE method and presence of client_id for /api/iam/v2/sessions.
Suppressed comments (1)

internal/logout/command_test.go:72

  • This test currently hard-codes the expected Auth0 client_id string. Deriving the expected value via the same sso helper used by deleteSession() avoids duplicating constants and keeps the test resilient to future client ID updates.
	// A httptest URL matches no known environment, so the client ID falls through to prod's.
require.Equal(t, "oX2nvSKl5jvBKVgwehZfvR4K8RhsZIEs", req.URL.Query().Get("client_id"))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 3 to 7
import (
"net/http"
"net/http/httptest"
"testing"

@sonarqube-confluent

Copy link
Copy Markdown

Quality Gate failedQuality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mcarle