Skip to content

feat: log in through OAuth 2.0 device code by default - #1402

Draft
vladfrangu wants to merge 1 commit into
masterfrom
feat/oauth-device-code-login
Draft

feat: log in through OAuth 2.0 device code by default#1402
vladfrangu wants to merge 1 commit into
masterfrom
feat/oauth-device-code-login

Conversation

@vladfrangu

@vladfrangu vladfrangu commented Sep 8, 2026

Copy link
Copy Markdown
Member

apify login now defaults to OAuth 2.0 against the Console authorization server instead of the bespoke Console hand-off. No new dependencies; native fetch and node:crypto only.

Flow (--method oauth2, the new default; console and manual unchanged, --token still short-circuits)

  • Device code first: prints the verification URL and code, opens the browser, polls the token endpoint at the server-provided interval.
  • Falls back to authorization code + PKCE on a loopback server, then to the legacy Console hand-off, but only on capability failures. A denied or expired login stops with an error; Ctrl+C prints Login cancelled.
  • Discovery is RFC 8414 from APIFY_CLI_OAUTH_ISSUER_URL (default https://console-backend.apify.com). The client ID is the URL of a client metadata document, APIFY_CLI_OAUTH_CLIENT_ID (default https://apify.com/.well-known/oauth-clients/apify-cli.json, served by apify/apify-web#6599).

Sessions

  • The access token is a regular Apify API token that expires after an hour, so resolveToken and getLocalUserInfo now go through getAccessToken, which refreshes when under 60 s remain or when the refresh token has under 30 min left. At most one refresh per process; a best-effort lock file plus an invalid_grant re-read handle concurrent CLIs, since the server rotates refresh tokens.
  • Refresh token lives in the keyring account oauth-refresh-token (inline in auth.json on the file backend); non-secret metadata in auth.json.oauth. Plain-token logins clear it. Logout removes it.
  • apify run requests a token with at least 45 min left and warns only if it could not get one. apify auth token notes the expiry on stderr.

Not in this PR

  • Until the apify-web PR ships, set APIFY_CLI_OAUTH_CLIENT_ID to a hosted copy of the document (CI needs this too).
  • Local Actor runs longer than an hour lose API access; needs longer-lived tokens or a refresh hook from the platform.
  • No revocation endpoint exists, so logout cannot invalidate the 60-day refresh token server-side.

The oauth2 method is the new default for apify login: device code first, then authorization code with PKCE on a loopback server, then the legacy Console hand-off. Access tokens are refreshed transparently before they expire; the refresh token lives in the OS keyring next to the token.
@github-actions github-actions Bot added this to the 149th sprint - Tooling team milestone Sep 8, 2026
@github-actions github-actions Bot added t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics. labels Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants