Skip to content

[client] Fall back to an available OAuth flow instead of hard-coding device code - #7186

Closed
lixmal wants to merge 1 commit into
mainfrom
auth-flow-fallback
Closed

[client] Fall back to an available OAuth flow instead of hard-coding device code#7186
lixmal wants to merge 1 commit into
mainfrom
auth-flow-fallback

Conversation

@lixmal

@lixmal lixmal commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes

Clients on Linux hosts pick the device code flow whenever no desktop environment is detected, and stay on it even when the server or the identity provider does not offer that flow, which fails the login instead of using PKCE.

  • Treat the device code flow as a preference rather than a fixed choice: fall back to the other flow when a flow is not configured on the server, comes back incomplete, or is refused by the identity provider when the flow is run, and keep failing on the preferred flow for unrelated errors
  • Improve graphical session detection by checking the variables that actually decide whether a browser can be opened (BROWSER, DESKTOP_SESSION, XDG_CURRENT_DESKTOP, DISPLAY, WAYLAND_DISPLAY, XDG_SESSION_TYPE), and let the desktop UI report a graphical session outright instead of inferring one
  • Fix netbird login --extend and SSH authentication always choosing the device code flow on Linux: both run in the daemon, which does not inherit the user's session environment, so they now take the answer from the caller, and their errors no longer suggest setup keys, which cannot extend a session or authenticate SSH

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)
  • I ran and tested this change locally — I did not rely on CI to find out whether it works
  • This PR has a single purpose (not a fix + refactor + feature in one)
  • This change is a trivial fix, OR it links an issue the NetBird team agreed on beforehand. Changes to the public API, gRPC protocols, functionality behavior, CLI / service flags, or new features always need that agreement first. See CONTRIBUTING.md.

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

The flow selection is internal to the client; no configuration or user-facing option changes.

Summary by CodeRabbit

  • New Features

    • Authentication now selects the most suitable available sign-in method, with automatic fallback when a provider does not support the preferred option.
    • Login and session extensions better recognize whether a graphical session is available.
    • Added clearer setup-key guidance when single sign-on is unavailable.
  • Bug Fixes

    • Improved handling of unsupported authentication configurations and preserved actionable errors during sign-in.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds graphical-session detection and propagates it through authentication requests. OAuth initialization now supports ordered PKCE and device-flow fallback. Unavailable SSO errors receive setup-key guidance.

Changes

OAuth session flow

Layer / File(s) Summary
Graphical-session detection and propagation
util/common.go, util/session_test.go, client/proto/daemon.proto, client/cmd/*, client/ssh/common.go, client/ui/*
HasGraphicalSession() detects session availability. Clients include the result in daemon authentication requests.
Ordered OAuth flow fallback
client/internal/auth/oauth.go, client/internal/auth/auth.go, client/internal/auth/pkce_flow.go, client/internal/auth/device_flow.go, client/internal/auth/oauth_test.go
OAuth initialization orders PKCE and device flows, classifies unavailable configurations, and falls back when authorization information rejects the selected flow.
Daemon and login integration
client/cmd/login.go, client/server/server.go
Daemon flows use the caller-provided graphical-session value. Login returns setup-key guidance when SSO is unavailable.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Daemon
  participant OAuthFlow
  participant IdentityProvider
  Client->>Daemon: Request authentication with hasGraphicalSession
  Daemon->>OAuthFlow: Create OAuth flow
  OAuthFlow->>IdentityProvider: Request authorization information
  IdentityProvider-->>OAuthFlow: Flow available or unavailable
  OAuthFlow-->>Daemon: Selected flow or fallback error
  Daemon-->>Client: Authentication result
Loading
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the changes and testing, but it omits the required issue ticket or approved discussion link for behavior changes. Add the agreed NetBird issue or discussion link and verify the prior-approval checklist item.
Linked Issues check ⚠️ Warning The issue ticket section is empty even though the PR changes behavior and adds protocol and exported API elements. Provide a link to the approved issue or discussion that authorizes these behavior and protocol changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: selecting an available OAuth flow instead of forcing device-code authentication.
Out of Scope Changes check ✅ Passed The changed files and tests align with the stated OAuth fallback, graphical-session detection, caller-state propagation, and error-handling objectives.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch auth-flow-fallback

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (7)
client/internal/auth/auth.go (1)

154-157: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse IsSSOUnavailable for the classification.

IsSSOUnavailable in client/internal/auth/oauth.go performs the same errors.As check. Call it here to keep one classification point.

♻️ Proposed fix
-		var ssoUnavailable *ssoUnavailableError
-		if errors.As(err, &ssoUnavailable) {
+		if IsSSOUnavailable(err) {
 			return backoff.Permanent(err)
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/auth.go` around lines 154 - 157, Update the error
classification in the retry flow to call IsSSOUnavailable(err) instead of
performing a local errors.As check against ssoUnavailableError, while preserving
the existing backoff.Permanent(err) behavior.
client/internal/auth/oauth.go (2)

214-218: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log the ignored authClient.Close() error.

Line 218 discards the error from Close(). The newAuth cleanup on Lines 226-230 logs the same failure at debug level. Use the same handling in both places.

As per coding guidelines: "Do not ignore write, network-send, or critical-cleanup errors; log ignored errors at debug or trace level".

♻️ Proposed fix
-	defer authClient.Close()
+	defer func() {
+		if err := authClient.Close(); err != nil {
+			log.Debugf("close auth client: %v", err)
+		}
+	}()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/oauth.go` around lines 214 - 218, The deferred cleanup
in the auth-client creation flow should not discard errors from
authClient.Close(). Update the defer associated with NewAuth to capture any
Close error and log it at debug level, matching the existing newAuth cleanup
handling and preserving the current return behavior.

Source: Coding guidelines


287-299: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Guard flowInitError against an empty error list.

If errs is empty, allMatch returns false and errors.Join() returns nil. The final fmt.Errorf("initialize authorization flow: %w", nil) then produces the text %!w(<nil>). The current callers always pass at least one error, so this is a latent trap only. Return an explicit error for the empty case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/oauth.go` around lines 287 - 299, Update flowInitError
to handle an empty errs slice before the allMatch checks and return an explicit
initialization error without calling errors.Join on nil; preserve the existing
SSO-specific and joined-error behavior when errs contains errors.
client/internal/auth/device_flow.go (1)

222-227: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider narrowing the OAuth error codes that trigger a flow change.

unsupported_grant_type and unauthorized_client indicate a disabled device grant. invalid_client usually indicates wrong client credentials, which affects the PKCE flow in the same way. For that case the client changes flow and then fails again, and the user sees the PKCE error instead of the credential error. The original error is preserved when no other flow is configured, so the impact is limited to the message the user reads.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/device_flow.go` around lines 222 - 227, Update the OAuth
error handling switch around oauthErr.Error to treat only unsupported_grant_type
and unauthorized_client as signals to change flows; remove invalid_client from
that set so credential errors do not trigger a misleading PKCE fallback, while
preserving the existing default false behavior.
client/cmd/login.go (2)

413-417: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated setup-key guidance text. Both call sites append the same sentence and documentation URL after auth.IsSSOUnavailable. The two copies can drift, and the URL must then be updated twice.

  • client/cmd/login.go#L413-L417: call a shared helper that adds the enrollment guidance to an SSO-unavailable error.
  • client/server/server.go#L685-L689: call the same helper here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/cmd/login.go` around lines 413 - 417, The setup-key guidance appended
to SSO-unavailable errors is duplicated. Add a shared helper for constructing
this enriched error, then update client/cmd/login.go lines 413-417 and
client/server/server.go lines 685-689 to call it instead of formatting the
message locally, keeping the guidance text and URL centralized.

123-123: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Confirm that the IsUnixDesktopClient proto field now carries graphical-session state.

The CLI now sends util.HasGraphicalSession() in IsUnixDesktopClient. The daemon forwards this field into the hasGraphicalSession parameter of auth.NewOAuthFlow (see client/server/server.go Line 682). The names no longer match the meaning, which makes the flow-selection contract hard to follow. Renaming the wire field would break compatibility, so add a comment in client/proto/daemon.proto that documents the current meaning, or introduce a new field and deprecate this one.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/cmd/login.go` at line 123, Document the current meaning of the
IsUnixDesktopClient proto field in client/proto/daemon.proto, stating that it
carries graphical-session state used by auth.NewOAuthFlow rather than strictly
identifying a Unix desktop client. Preserve the existing field and wire
compatibility; do not rename it.
client/internal/auth/oauth_test.go (1)

160-207: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a case for a failing authFactory.

fallbackFlow.initNext returns early when newAuth fails, and RequestAuthInfo then returns the original error. stubAuthFactory always succeeds, so this branch stays untested. A subtest with a factory that returns an error would cover it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/oauth_test.go` around lines 160 - 207, Add a subtest in
TestFallbackFlowRequestAuthInfo that uses an authFactory returning an error,
exercises the fallback path through RequestAuthInfo, and verifies the factory
error is returned while the original flow remains active. Reuse the existing
flow setup and assertions where applicable, targeting fallbackFlow.initNext
behavior rather than changing production code.
🤖 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 `@client/internal/auth/oauth.go`:
- Around line 144-153: The fallback path in initNext must not read the shared
Auth.client field without synchronization. In
client/internal/auth/oauth.go:144-153, obtain the management client through the
mutex-protected accessor or pass a captured client into initFirstAvailableFlow;
in client/internal/auth/auth.go:145-148, return the client already captured
under RLock by withRetry so the shared field is not reread. Run go test -race
./client/internal/auth/... after the change.

In `@client/server/server.go`:
- Around line 685-689: Update the auth.IsSSOUnavailable(err) branch to return a
gRPC status error using a terminal code handled by the login CLI, while
preserving the existing setup-key guidance and underlying error context.

In `@util/common.go`:
- Around line 19-24: Define private constants for all browser graphical-session
environment-variable names in util/common.go, then build browserSessionEnvVars
and the session-type lookup at util/common.go lines 19-24 and 44-44 from those
constants. Update util/session_test.go lines 18-18 and 30-38 to use the same
shared constants when clearing inherited state and populating table env values,
keeping names centralized and eliminating duplicate literals.

---

Nitpick comments:
In `@client/cmd/login.go`:
- Around line 413-417: The setup-key guidance appended to SSO-unavailable errors
is duplicated. Add a shared helper for constructing this enriched error, then
update client/cmd/login.go lines 413-417 and client/server/server.go lines
685-689 to call it instead of formatting the message locally, keeping the
guidance text and URL centralized.
- Line 123: Document the current meaning of the IsUnixDesktopClient proto field
in client/proto/daemon.proto, stating that it carries graphical-session state
used by auth.NewOAuthFlow rather than strictly identifying a Unix desktop
client. Preserve the existing field and wire compatibility; do not rename it.

In `@client/internal/auth/auth.go`:
- Around line 154-157: Update the error classification in the retry flow to call
IsSSOUnavailable(err) instead of performing a local errors.As check against
ssoUnavailableError, while preserving the existing backoff.Permanent(err)
behavior.

In `@client/internal/auth/device_flow.go`:
- Around line 222-227: Update the OAuth error handling switch around
oauthErr.Error to treat only unsupported_grant_type and unauthorized_client as
signals to change flows; remove invalid_client from that set so credential
errors do not trigger a misleading PKCE fallback, while preserving the existing
default false behavior.

In `@client/internal/auth/oauth_test.go`:
- Around line 160-207: Add a subtest in TestFallbackFlowRequestAuthInfo that
uses an authFactory returning an error, exercises the fallback path through
RequestAuthInfo, and verifies the factory error is returned while the original
flow remains active. Reuse the existing flow setup and assertions where
applicable, targeting fallbackFlow.initNext behavior rather than changing
production code.

In `@client/internal/auth/oauth.go`:
- Around line 214-218: The deferred cleanup in the auth-client creation flow
should not discard errors from authClient.Close(). Update the defer associated
with NewAuth to capture any Close error and log it at debug level, matching the
existing newAuth cleanup handling and preserving the current return behavior.
- Around line 287-299: Update flowInitError to handle an empty errs slice before
the allMatch checks and return an explicit initialization error without calling
errors.Join on nil; preserve the existing SSO-specific and joined-error behavior
when errs contains errors.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 88bcee06-e97e-4ba7-bf44-fc6ee32183bd

📥 Commits

Reviewing files that changed from the base of the PR and between c5503fd and 0f59345.

⛔ Files ignored due to path filters (1)
  • client/proto/daemon.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (14)
  • client/cmd/login.go
  • client/cmd/up.go
  • client/internal/auth/auth.go
  • client/internal/auth/device_flow.go
  • client/internal/auth/oauth.go
  • client/internal/auth/oauth_test.go
  • client/internal/auth/pkce_flow.go
  • client/proto/daemon.proto
  • client/server/server.go
  • client/ssh/common.go
  • client/ui/authsession/service.go
  • client/ui/services/connection.go
  • util/common.go
  • util/session_test.go

Comment on lines +144 to 153
a, cleanup, err := f.newAuth(ctx)
if err != nil {
return nil, err
}
defer cleanup()

flow, remaining, err := initFirstAvailableFlow(a, a.client, f.remaining, f.hint)
if err != nil {
log.Debugf("failed to initialize pkce authentication with error: %v\n", err)
log.Debug("falling back to device code flow")
return authenticateWithDeviceCodeFlow(ctx, config, hint)
return nil, err
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unsynchronized read of Auth.client in the fallback path. initNext reads a.client directly, while Auth.reconnect can reassign that field and Auth.Close can set the connection unusable, both under Auth.mutex. In the GetOAuthFlow path the factory returns the same long-lived Auth, and withRetry reconnects on connection errors, so a fallback can read the field while another goroutine replaces it.

  • client/internal/auth/oauth.go#L144-L153: read the management client through an accessor that takes Auth.mutex (as Auth.Close and withRetry do) instead of reading a.client directly, or pass the client in from the caller.
  • client/internal/auth/auth.go#L145-L148: this factory hands out the shared a, which makes the unsynchronized read reachable; return the client that withRetry already captured under RLock so the fallback does not re-read the field.

Run go test -race ./client/internal/auth/... after the change.

As per coding guidelines: "Protect shared mutable state with a mutex, atomic, or channel as appropriate; perform a two-pass race analysis and run go test -race on touched packages after concurrency changes" and "Do not read a mutable struct field inside a goroutine when another goroutine can nil or reassign it; capture it locally or pass it as a parameter".

📍 Affects 2 files
  • client/internal/auth/oauth.go#L144-L153 (this comment)
  • client/internal/auth/auth.go#L145-L148
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/auth/oauth.go` around lines 144 - 153, The fallback path in
initNext must not read the shared Auth.client field without synchronization. In
client/internal/auth/oauth.go:144-153, obtain the management client through the
mutex-protected accessor or pass a captured client into initFirstAvailableFlow;
in client/internal/auth/auth.go:145-148, return the client already captured
under RLock by withRetry so the shared field is not reread. Run go test -race
./client/internal/auth/... after the change.

Source: Coding guidelines

Comment thread client/server/server.go
Comment on lines +685 to +689
// enrolling a device is the one flow a setup key can replace
if auth.IsSSOUnavailable(err) {
return nil, fmt.Errorf("%w. Set this device up with a setup key instead: "+
"https://docs.netbird.io/how-to/register-machines-using-setup-keys", err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Return a terminal gRPC status code for the SSO-unavailable case.

This branch reports a permanent condition: the management server offers no usable SSO flow. fmt.Errorf produces codes.Unknown at the RPC boundary. In client/cmd/login.go Lines 148-156, the CLI stops its backoff loop only for InvalidArgument, PermissionDenied, NotFound, and Unimplemented. With codes.Unknown the CLI retries the login until the backoff window expires, so the user waits instead of seeing the setup-key guidance.

Wrap the message in a status with a code that the CLI treats as terminal.

🔧 Proposed fix
 			// enrolling a device is the one flow a setup key can replace
 			if auth.IsSSOUnavailable(err) {
-				return nil, fmt.Errorf("%w. Set this device up with a setup key instead: "+
-					"https://docs.netbird.io/how-to/register-machines-using-setup-keys", err)
+				return nil, gstatus.Errorf(codes.NotFound,
+					"%v. Set this device up with a setup key instead: "+
+						"https://docs.netbird.io/how-to/register-machines-using-setup-keys", err)
 			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// enrolling a device is the one flow a setup key can replace
if auth.IsSSOUnavailable(err) {
return nil, fmt.Errorf("%w. Set this device up with a setup key instead: "+
"https://docs.netbird.io/how-to/register-machines-using-setup-keys", err)
}
// enrolling a device is the one flow a setup key can replace
if auth.IsSSOUnavailable(err) {
return nil, gstatus.Errorf(codes.NotFound,
"%v. Set this device up with a setup key instead: "+
"https://docs.netbird.io/how-to/register-machines-using-setup-keys", err)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/server/server.go` around lines 685 - 689, Update the
auth.IsSSOUnavailable(err) branch to return a gRPC status error using a terminal
code handled by the login CLI, while preserving the existing setup-key guidance
and underlying error context.

Comment thread util/common.go
Comment on lines +19 to +24
// browserSessionEnvVars returns the variables that decide whether OpenBrowser can open a URL:
// BROWSER is the explicit override it honors first, DESKTOP_SESSION and XDG_CURRENT_DESKTOP are
// what xdg-open uses to pick a handler, and DISPLAY / WAYLAND_DISPLAY are what any graphical
// browser it launches needs.
func browserSessionEnvVars() []string {
return []string{"BROWSER", "DESKTOP_SESSION", "XDG_CURRENT_DESKTOP", "DISPLAY", "WAYLAND_DISPLAY"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Define the graphical-session environment-variable names once.

The production helper and its tests use separate string literals for the same environment-variable names. Define private constants in util/common.go and use them at every site.

  • util/common.go#L19-L24: build browserSessionEnvVars from private environment-variable constants.
  • util/common.go#L44-L44: use the XDG session-type constant for the lookup.
  • util/session_test.go#L18-L18: use the XDG session-type constant when clearing inherited state.
  • util/session_test.go#L30-L38: use the shared constants as table env values.

As per coding guidelines: “Declare environment-variable names as constants.”

📍 Affects 2 files
  • util/common.go#L19-L24 (this comment)
  • util/common.go#L44-L44
  • util/session_test.go#L18-L18
  • util/session_test.go#L30-L38
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@util/common.go` around lines 19 - 24, Define private constants for all
browser graphical-session environment-variable names in util/common.go, then
build browserSessionEnvVars and the session-type lookup at util/common.go lines
19-24 and 44-44 from those constants. Update util/session_test.go lines 18-18
and 30-38 to use the same shared constants when clearing inherited state and
populating table env values, keeping names centralized and eliminating duplicate
literals.

Source: Coding guidelines

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Release artifacts

Built for PR head 0f59345 in workflow run #17747.

Artifact Link
All release artifacts Download
Linux packages Download
Windows packages Download
macOS packages Download
UI artifacts Download
UI GTK3 artifacts Download
UI macOS artifacts Download

GHCR images (amd64)

This comment is updated by the Release workflow. Artifact links expire according to the workflow retention policy.

@lixmal lixmal closed this Aug 12, 2026
@lixmal
lixmal deleted the auth-flow-fallback branch August 12, 2026 18:59
@lixmal

lixmal commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #7187 (session extension / SSH auth flow selection) and #7188 (fallback between authorization flows), which split this change in two. The review findings from this PR are addressed in those.

Sign up for free to 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.

1 participant