Skip to content

feat(api, cmd): Add PKCE-based authentication flow with CLI integration and tests#79

Draft
tiulpin wants to merge 1 commit intomainfrom
tv/pkce
Draft

feat(api, cmd): Add PKCE-based authentication flow with CLI integration and tests#79
tiulpin wants to merge 1 commit intomainfrom
tv/pkce

Conversation

@tiulpin
Copy link
Member

@tiulpin tiulpin commented Feb 3, 2026

Summary

Adds PKCE (RFC 7636) OAuth flow for browser-based authentication. Users can now log in via browser instead of manually copying tokens.

Changes

API (internal/api/pkce.go)

  • PKCE utilities: code verifier/challenge generation (S256), state parameter
  • Local callback server on ports 19000-19100
  • Token exchange with context support

CLI (internal/cmd/auth.go)

  • tc auth login now tries PKCE first, falls back to manual token entry
  • --no-browser flag to skip PKCE
  • --scopes flag for custom permissions

Design Decisions

Port range 19000-19100: Avoids common dev ports (3000, 8080, etc.) to reduce conflicts., FindAvailableListener()` returns an open listener to avoid TOCTOU race between finding and binding a port.

Scope handling: We request all scopes needed for full CLI functionality. The server filters to only grant what it allows.

// View (read-only)
"VIEW_PROJECT",
"VIEW_BUILD_CONFIGURATION_SETTINGS",
"VIEW_AGENT_DETAILS",

// Builds
"RUN_BUILD",
"CANCEL_BUILD",
"TAG_BUILD",
"COMMENT_BUILD",
"PIN_UNPIN_BUILD",
"REORDER_BUILD_QUEUE",
"PATCH_BUILD_SOURCES",

// Jobs
"PAUSE_ACTIVATE_BUILD_CONFIGURATION",
"EDIT_BUILD_CONFIGURATION",

// Projects
"EDIT_PROJECT",

// Agents
"ENABLE_DISABLE_AGENT",
"AUTHORIZE_AGENT",
"ADMINISTER_AGENT",
"CONNECT_TO_AGENT",

// Pools
"MANAGE_AGENT_POOLS"

Right now, the server requires the special feature flag enabled to have PKCE activated and provides limited permissions:

VIEW_PROJECT
VIEW_BUILD_CONFIGURATION_SETTINGS 
VIEW_AGENT_DETAILS
RUN_BUILD 
PATCH_BUILD_SOURCES

So this pull request will be merged once the new permission set is agreed.

Example

$ tc auth login
✓ Detected server from .teamcity/pom.xml
ℹ Secure browser login enabled on this server
ℹ Opening browser for authentication...
  → Approve access in TeamCity

✓ Logged in as John Doe
ℹ Token expires: Mar 3, 2026
ℹ Note: Browser login supports viewing and triggering builds.
ℹ For tagging/pinning/canceling, create a manual API token in your profile.

Configuration saved to ~/.config/tc/config.json

Test Plan

  • Tests pass (go test ./...)
  • Linter passes (golangci-lint run)
  • Manually tested with a PKCE-enabled server

@tiulpin tiulpin added the blocked:needs-api Blocked - requires server-side API support label Feb 3, 2026
@tiulpin tiulpin force-pushed the tv/pkce branch 2 times, most recently from 01bf72a to 9c59149 Compare February 3, 2026 15:44

if result.Error != "" {
w.WriteHeader(http.StatusBadRequest)
_, _ = fmt.Fprintf(w, `<!DOCTYPE html><html><head><title>TeamCity CLI</title>
Copy link
Member

Choose a reason for hiding this comment

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

Curious, is it normal to embed HTML like this? Maybe some template engine could be used, or do you think it's overkill in this case?

// AvailableScopes lists permissions to request via PKCE.
// The server filters these to only grant what it allows.
var AvailableScopes = []string{
// View (read-only)
Copy link
Member

Choose a reason for hiding this comment

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

I am a bit worried that we're having a list of permissions embedded here. I think it would be better to have a REST API endpoint on TeamCity side which would provide this list.

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

Labels

blocked:needs-api Blocked - requires server-side API support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants