Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/agent/src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,12 +609,15 @@ where
let remote_discovery = inventory.clone();
let state_dir = args.state_dir.clone();
let oidc_callback_listen = args.oidc_callback_listen;
// A system-mode daemon is root: its browser would not be the user's.
let open_browser = args.user;
let remote_enrollment = enrollment.clone();
tokio::spawn(remote::run(
controller,
remote_discovery,
state_dir,
oidc_callback_listen,
open_browser,
reconciler,
remote_enrollment,
controller_status.clone(),
Expand Down
5 changes: 4 additions & 1 deletion crates/agent/src/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ pub async fn enroll(
controller: &ControllerConnectionConfig,
enrollment: &EnrollmentState,
callback_listen: Option<SocketAddr>,
open_browser: bool,
) -> anyhow::Result<Identity> {
if controller.device_authorization {
return enroll_with_device_authorization(controller, enrollment).await;
Expand All @@ -315,6 +316,7 @@ pub async fn enroll(
&redirect_uri,
std::mem::take(&mut begin.state),
callback_listen,
open_browser,
)
.await?;
enrollment.set("enrolling").await;
Expand Down Expand Up @@ -631,6 +633,7 @@ pub(crate) async fn wait_for_authorization_code(
redirect_uri: &Url,
expected_state: String,
callback_listen: Option<SocketAddr>,
open_browser: bool,
) -> anyhow::Result<String> {
wait_for_authorization_code_with_page(
authorization_url,
Expand All @@ -641,7 +644,7 @@ pub(crate) async fn wait_for_authorization_code(
subscription_available: false,
github_available: false,
},
true,
open_browser,
)
.await?
.context("required authorization was skipped")
Expand Down
5 changes: 4 additions & 1 deletion crates/agent/src/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ pub async fn run(
mut discovered: watch::Receiver<Arc<AgentDiscovery>>,
state_dir: PathBuf,
oidc_callback_listen: Option<SocketAddr>,
open_browser: bool,
reconciler: Reconciler,
enrollment: EnrollmentState,
controller_status: ControllerConnectionState,
Expand All @@ -207,6 +208,7 @@ pub async fn run(
&mut discovered,
&state_dir,
oidc_callback_listen,
open_browser,
&reconciler,
&enrollment,
&controller_status,
Expand Down Expand Up @@ -304,6 +306,7 @@ async fn run_session(
discovered: &mut watch::Receiver<Arc<AgentDiscovery>>,
state_dir: &Path,
oidc_callback_listen: Option<SocketAddr>,
open_browser: bool,
reconciler: &Reconciler,
enrollment: &EnrollmentState,
controller_status: &ControllerConnectionState,
Expand Down Expand Up @@ -338,7 +341,7 @@ async fn run_session(
enrollment,
logout,
INITIAL_RETRY_DELAY,
|| oidc::enroll(controller, enrollment, oidc_callback_listen),
|| oidc::enroll(controller, enrollment, oidc_callback_listen, open_browser),
)
.await;
identity::save(&identity_path, &identity)?;
Expand Down
25 changes: 13 additions & 12 deletions docs/device-identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ sequenceDiagram
Controller-->>Daemon: enrollment_id, authorization_url, state, redirect_uri, token_endpoint, client_id
Daemon->>Daemon: Listen on loopback redirect_uri (default 127.0.0.1:51327)
Daemon->>Daemon: Publish authorization_url on GET /v1/enrollment and wait up to 10 min
alt Daemon runs as a system service (normal install)
Note over Daemon: Cannot open a browser. It runs outside any user session.
alt Daemon runs in system mode (normal install)
Note over Daemon: Does not open a browser. It runs as root, outside the user's session.
User->>App: Sign in
App->>Daemon: GET /v1/enrollment
Daemon-->>App: authorization_url
App->>Browser: Open authorization_url
else Daemon runs in the user's session (sudo, user mode, development)
else Daemon runs in user mode (--user, development)
Daemon->>Browser: Open the local sign-in page
User->>Browser: Continue to sign in
end
Expand Down Expand Up @@ -217,15 +217,16 @@ native app (RFC 8252):
(default `http://127.0.0.1:51327/callback`) and publishes the
authorization URL on `/v1/enrollment`. How the browser gets there depends
on how the daemon runs:
- **As a system service** (the normal install: LaunchDaemon, Windows
service, systemd), the daemon runs outside any user session and cannot
open a browser. Its attempt to do so fails and is only logged. The user
clicks sign-in in the desktop app, which reads the URL from
`/v1/enrollment` and opens it in the user's browser. The browser goes
straight to the IdP.
- **In the user's session** (`sudo` from a terminal, `--user` mode,
development), the daemon opens the browser on its own landing page, and
**Continue to sign in** redirects to the IdP.
- **In system mode** (the normal install: LaunchDaemon, Windows service,
systemd; also `sudo agentdesktop daemon` from a terminal), the daemon
runs as root and does not open a browser. Such an attempt would not
simply fail: on macOS, `open` run by root starts Safari on the daemon's
landing page instead of the user's browser. The user clicks sign-in in
the desktop app, which reads the URL from `/v1/enrollment` and opens it
in the user's browser. The browser goes straight to the IdP.
- **In user mode** (`--user`, development), the daemon opens the browser
on its own landing page, and **Continue to sign in** redirects to the
IdP.

`agentdesktop enrollment` prints the same URL.
5. After the user authenticates, the IdP redirects to the loopback callback.
Expand Down