Skip to content

Shared O11y OAuth onboarding and export controls#133

Draft
tilakchowdary wants to merge 1 commit into
signalfx:mainfrom
tilakchowdary:feat/o11y-ide-oauth-pkce
Draft

Shared O11y OAuth onboarding and export controls#133
tilakchowdary wants to merge 1 commit into
signalfx:mainfrom
tilakchowdary:feat/o11y-ide-oauth-pkce

Conversation

@tilakchowdary

@tilakchowdary tilakchowdary commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a shared Obstudio onboarding path for Splunk Observability Cloud:

  • obstudio cloud register opens the Splunk Observability Cloud Free registration page.
  • obstudio cloud login runs authorization-code OAuth with PKCE in the Go binary.
  • obstudio cloud status returns redacted connection metadata.
  • obstudio cloud logout revokes the server token before deleting the local credential.
  • VS Code and Cursor delegate OAuth and revocation to the bundled Go binary instead of maintaining a second TypeScript protocol client.
  • Standalone Obstudio uses the OS keychain; VS Code and Cursor use IDE SecretStorage.
  • $splunk-o11y-onboard wraps the same commands for Codex, Claude Code, and Cursor.
  • Local telemetry storage remains active; remote export stays off until the user enables it.

Companion changes:

User flows

New organization

obstudio cloud register

Obstudio opens the Splunk-hosted Free registration page. The user completes registration and email verification in the browser, then connects the resulting organization with cloud login.

Existing organization

obstudio cloud login --issuer https://app.<realm>.signalfx.com

The browser reuses the user's existing Splunk Observability Cloud session. The Splunk-hosted page owns organization context, consent, and optional-scope selection.

OAuth call flow

1. Authorization-server discovery

Go OAuth client -> realm-specific Splunk Observability Cloud issuer:

GET https://app.<realm>.signalfx.com/.well-known/oauth-authorization-server
Accept: application/json

The response supplies the exact issuer plus /oauth/authorize, /v2/oauth/token, and /v2/oauth/revoke. Obstudio requires authorization code, query response mode, public clients, PKCE S256, revocation, and authorization-response iss support. All endpoints must use the configured issuer origin.

2. Browser authorization

The Go client binds 127.0.0.1:<random-port>/callback, creates a 256-bit state and PKCE verifier, then opens:

GET https://app.<realm>.signalfx.com/oauth/authorize
  ?response_type=code
  &client_id=<registered-client>
  &redirect_uri=http://127.0.0.1:<port>/callback
  &scope=ingest%20api
  &state=<random-state>
  &code_challenge=<S256-challenge>
  &code_challenge_method=S256
  &token_name=<display-name>

Registered clients include obstudio-cli, obstudio-vscode, and obstudio-cursor. No access token is placed in the browser URL or exposed to browser JavaScript.

3. Consent and authorization code

SignalView uses the existing authenticated browser session to call App Platform:

POST /v2/oauth/authorization-context
POST /v2/oauth/authorization-decisions
X-SF-TOKEN: <browser-session-token>

App Platform validates the registered client, exact loopback redirect shape, requested scopes, and PKCE challenge. Approval returns a short-lived one-time code and issuer. The browser redirects:

GET http://127.0.0.1:<port>/callback
  ?code=<authorization-code>
  &state=<state>
  &iss=https%3A%2F%2Fapp.<realm>.signalfx.com

Obstudio accepts exactly one callback only after exact state and iss validation.

4. PKCE token exchange

Go OAuth client -> App Platform:

POST https://app.<realm>.signalfx.com/v2/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
client_id=<registered-client>&
code=<authorization-code>&
redirect_uri=http%3A%2F%2F127.0.0.1%3A<port>%2Fcallback&
code_verifier=<original-verifier>

Successful response:

{
  "access_token": "<scoped-token>",
  "token_type": "Bearer",
  "expires_in": 31536000,
  "scope": "ingest api",
  "splunk_issuer": "https://app.<realm>.signalfx.com",
  "splunk_realm": "<realm>",
  "splunk_ingest_endpoint": "https://ingest.<realm>.signalfx.com",
  "splunk_org_id": "<org-id>",
  "splunk_token_id": "<token-id>",
  "splunk_token_name": "<token-name>"
}

Obstudio verifies the issuer, bearer type, required ingest scope, granted-scope subset, realm, and canonical ingest endpoint before accepting the connection.

5. Secure storage and Observer configuration

Standalone CLI stores the connection in macOS Keychain, Windows Credential Manager, or Linux Secret Service. A later standalone Observer loads only an unexpired key with ingest; environment credentials take precedence.

VS Code and Cursor invoke the bundled binary with an explicit session-only JSON handoff, capture stdout, and immediately store the connection in IDE SecretStorage. If IDE persistence fails, the extension revokes the newly issued token before returning an error.

The extension configures its managed Observer over the loopback control API:

POST http://127.0.0.1:<observer-port>/api/splunk/export
Authorization: Bearer <observer-control-token>
Content-Type: application/json

{
  "accessToken": "<scoped-token>",
  "enabled": false,
  "endpoint": "https://ingest.<realm>.signalfx.com",
  "issuer": "https://app.<realm>.signalfx.com",
  "realm": "<realm>",
  "timeoutSeconds": 5
}

The response is redacted. Export remains disabled until explicitly enabled; when enabled, telemetry continues to be stored locally and is also sent remotely.

6. Logout / Forget key

POST https://app.<realm>.signalfx.com/v2/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=<scoped-token>&token_type_hint=access_token

Only after successful revocation does Obstudio delete the OS-keychain or IDE SecretStorage connection. --local-only is an explicit break-glass option.

Security properties

  • Authorization code with PKCE S256 for public clients
  • Random loopback port, exact callback path, one-shot callback
  • State and authorization-response issuer validation
  • Exact issuer-origin metadata and endpoint binding
  • Registered client, redirect, and scope enforcement in App Platform
  • No access token in browser URLs, process arguments, logs, normal CLI output, or UI
  • Bounded HTTP responses, child-process output, and stdin connection payloads
  • Server-side token revocation on logout and persistence failure
  • IDE SecretStorage first; OS keychain for standalone use; no plaintext fallback
  • Separate local Observer control token for privileged export operations

Verification

  • make test-all: passed
  • Go packages: passed, including OAuth loopback/PKCE, keychain adapter, CLI lifecycle, and startup precedence tests
  • Client: 125 tests passed
  • Extension: 74 unit tests passed
  • Packaged VSIX integration/smoke: 13 tests passed
  • VS Code host: 15 passed, 1 pending
  • Linux amd64, Windows amd64, and macOS arm64 Go builds: passed
  • Cross-repository OAuth contract check: passed against Obstudio, SignalView, and App Platform
  • Skill validation: passed
  • Combined hosted-PR, independent baseline, and Claude Opus review: no remaining findings

@tilakchowdary tilakchowdary force-pushed the feat/o11y-ide-oauth-pkce branch 3 times, most recently from 6e16b73 to 8bd5438 Compare June 30, 2026 03:53
@tilakchowdary tilakchowdary changed the title OAuth PKCE connection and Splunk O11y export controls Shared O11y OAuth onboarding and export controls Jun 30, 2026
@tilakchowdary tilakchowdary force-pushed the feat/o11y-ide-oauth-pkce branch 2 times, most recently from 1bfba39 to 8fee1df Compare June 30, 2026 06:04
@tilakchowdary tilakchowdary force-pushed the feat/o11y-ide-oauth-pkce branch from 8fee1df to 98d6b85 Compare June 30, 2026 06:16
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