Skip to content

Handle various auth credentials, remove dashboard and network packages#39

Merged
austin-denoble merged 23 commits intomainfrom
adenoble/implement-credentials-logic
Sep 26, 2025
Merged

Handle various auth credentials, remove dashboard and network packages#39
austin-denoble merged 23 commits intomainfrom
adenoble/implement-credentials-logic

Conversation

@austin-denoble
Copy link
Collaborator

@austin-denoble austin-denoble commented Sep 15, 2025

Problem

There are two big issues around authentication this PR is trying to address.

First, we're not refreshing our oauth user tokens after initially retrieving one on login (pc auth login). This means that after 30 minutes, the token is no longer valid and the user will have to log in again. We need to make sure that we're calling for a refreshed token if the local token is expired. There were changes merged to the auth0-config to support this for the Pinecone CLI client.

Second, the CLI previously relied on the non-public dashboard APIs in order to work with organizations, projects, and API keys. These implementations were handled manually through the network and dashboard packages. In a previous PR, the code for working with admin resources was mostly replaced when implementing commands for project, organization, and api-key. However, we are still using dashboard APIs for the login and target flows.

Additionally, because of how our systems currently work with authentication, the CLI needs additional business logic for working with the control and data plane APIs when the user has authenticated via a user token (pc auth login) or a service account (pc auth configure --client-id --client-secret). Because there are limitations on where these tokens can be used across APIs surfaces, the CLI needs mechanisms for creating its own API keys, and allowing users to "store" keys for specific projects. This in turn means we need to expose ways for users to manage these locally stored keys themselves.

If you're curious or have any feedback, I've captured notes and thoughts here while working on an approach that will work for the CLI with our current authentication structure.

Solution

While it's a large PR, there haven't been any breaking changes made to the existing CLI interface. A lot of the credentials management logic is mostly abstracted from the user, but there are a number of new flags for existing commands that allow better ease-of-use when working with resources. Additionally, there has been new sub-commands added under pc auth to allow listing and pruning "local keys". I'll try and break things into sections below for review and testing focus.

Supporting oauth user token refresh

Previously, the CLI would get an oauth user token on pc auth login, store it once using secrets.OAuth2Token.Set(), and that was it. Since any code paths that needed the token for building the SDK would just pull it directly out of secrets.OAuth2Token.Get(), there was never any token refresh happening when expiry was reached.

It's also not great that we have a lot of logic directly getting and setting against our Viper storage (local config files). This will lead to race conditions if multiple calls are made getting/setting within the same process, or if there are concurrent processes accessing these things (IE: a user having multiple shells opens running things using the CLI). Some of this is more forward-thinking, but I tried to be aware of it as I worked on an implementation to handle refreshing tokens.

Ultimately, I decided on writing a TokenManager singleton (sync.Once), that exposes a method Token for anywhere that needs access to the user token. This effectively acts as a wrapper for the secrets package where I've added a sync.RWMutex along with getters and setters for the underlying Viper MarshaledProperty. I've also made the property itself local so it's not directly exported from the secrets package. We should most likely do this for anything we're storing locally, but I've held off refactoring everything for now.

  • Implement TokenManager. Add a public Token() function to the oauth package which returns TokenManager.Token(). Implement logic for refreshing when needed. Implement custom HTTP logic for calling for a refresh in refreshTokenWithOrg. We need to do this because we need to pass orgId in the body or the refreshed token will default to a different org, and the Go oauth2 package doesn't inherently support this.
  • Rename the oauth2 package to oauth in utils.
  • Replace all instances of calling secrets.OAuth2Token.Get() directly with oauth.Token().

Handling multiple types of "auth"

There are a lot of changes and general refactoring in this PR to smooth out the experience of having several different forms of authentication that the user could be working with. The current primary forms of authentication are:

  • User Token (pc auth login)
  • Service Account Credentials (pc auth configure --client-id --client-secret)
  • Global API Key (pc config set-api-key or pc auth configure --api-key)
Admin API access Control Plane access Data Plane access v3 Data Plane Access
User Token ✅ (with X-Project-Id header) ✅ (with X-Project-Id header)
Service Account
Global API Key

Because of the variation in levels of access currently in our auth systems, the CLI needs to allow users to create new keys and store them locally for later use. Additionally, the CLI needs to be able to create its own managed keys if the user does not explicitly create keys before working with the control or data plane APIs. Currently, the console does a form of this by generating a "default" API key when you first log in. The console has access to unstable APIs that allow them to more easily work with API keys generally, so we have to make some concessions in the CLI where we're relying on the public admin APIs.

  • "Global" API key set via pc auth configure --api-key or pc config set-api-key will override the target organization, project, and any internally managed keys. This applies to operations involving the control and data plane (index, collections, etc). NOTE: We most likely need better documentation and messaging around this behavior. Any suggestions would be great.
  • Add pc auth clear --global-api-key --service-account to allow users a way to remove any configurations they've provided.
  • Add pc auth status to print out a detailed summary of the current authentication credentials that are configured.
  • User Token & Service Account credentials are now mutually exclusive. If you call pc auth configure --client-id --client-secret after pc auth login and vice versa, it will log you out or clear the previously set credentials. This will also reset the current Organization and Project target because service accounts are scoped to a single organization.
  • After calling pc auth configure --client-id --client-secret, the CLI will use the admin API to fetch organization and project information, allowing the user to accurately target their org and project.

Storing "managed" keys locally is a part of handling auth, and is explained a bit more below.

Managed Keys (locally stored map[project_id]:ManagedKey)

Because of limitations described previously, the CLI needs to have some concept of maintaining API keys for projects locally that can be reused across actions. There's no way to fetch an API keys value after the initial create call through the public Admin API. There's also no way to determine a keys organization or project if we just have access to the raw value, such as when a global API key is configured. There are also a lot of possible edge cases around an API key being used and then deleted outside of the CLI context, or manually by a user through the CLI.

My approach to resolving some of these issues and presenting a streamlined experience within the CLI is to introduce the concept of ManagedKeys. These are keys that the CLI is essentially managing in state, and they can either be created manually by a user through the CLI, or the CLI will create one to manage itself if the user has not created one explicitly.

The map of project keys is stored locally in a new MarshaledProperty in the secrets Viper store. Check secrets.go to see the implementation of that along with the struct definition for ManagedKey. The logic for creating "cli-managed" keys is in the sdk package, and is tied to when we instantiate the Pinecone Go SDK. If the CLI needs to create its own key for management, this will be seamless to the user if they call something that requires it, like pc index list.

In order to manage keys that are stored locally, there are new flags and commands exposed in a few places.

  • pc api-key create --name "your-key-name" --store - the --store flag is new, telling the CLI to store this new key for the project it was created in locally. If there was a previously cli-managed key stored, it will be cleaned up.
  • pc auth local-keys list - this will list all the project keys the CLI is maintaining locally in state.
  • pc auth local-keys prune --dry-run --skip-confirmation - this prune command allows cleaning up locally maintained keys. It has flags for filtering what gets deleted: --dry-run will output planned changes without applying anything, --skip-confirmation will skip the deletion confirmation, --id allows cleaning up only one project, and --origin allows cleaning up user-created keys, cli-created keys, or all keys.
  • pc api-key delete - this command will now check to see if you're deleting the currently stored key for the project, and remove the locally cached key if you do.

I don't think this approach is perfect, but I think for right now it gives us a pretty good overall experience while exposing options for managing your current state. Definitely open to feedback on this approach, and I think things will be evolving more as we move forward.

Removing dashboard and network packages

These packages are no longer needed due to the above changes, and we can safely remove all dependencies on the console admin API.

If you read all this, thank you!

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Infrastructure change (CI configs, etc)
  • Non-code change (docs, etc)
  • None of the above: (explain here)

Test Plan

The simplest way to test these changes locally are going to be checking out this branch (adenoble/implement-credentials-logic) locally, and running goreleaser to build the binary. Then just run off of that as you normally would.

$ git checkout adenoble/implement-credentials-logic
$ goreleaser build --single-target --snapshot --clean

# run commands against the binary
$ ./dist/pc_darwin_arm64/pc auth login

I would recommend testing using each authentication approach. Using pc auth status and pc target --show to double check which organization and project you're targeting will be really helpful for validating things. When doing things like swapping your targeted project, you'll want to follow up with a control plane call like pc index list.

Here's an example of a testing flow I've used locally to get started:

$ ./dist/pc_darwin_arm64/pc auth login
[SUCCESS] Logged in as austin.d@pinecone.io. Defaulted to organization ID: -NF9kuQiPWth9QLPg5NS

[INFO] Target org set to pinecone-official.
[INFO] Target project set cmek-integration-tests.

$ ./dist/pc_darwin_arm64/pc auth status
ATTRIBUTE                        VALUE
Authentication Mode              user_token
Global API Key                   UNSET
Service Account Client ID        UNSET
Service Account Client Secret    UNSET
Token Expiry                     2025-09-23T20:33:40-04:00
Token Time Remaining             29m13s
Token Scope                      openid profile email offline_access
Token Organization ID            -NF9kuQiPWth9QLPg5NS
Environment                      production

$ ./dist/pc_darwin_arm64/pc target --org "SDK Testing" --project pinecone-cli
[SUCCESS] Target org updated to SDK Testing
[SUCCESS] Target project updated to pinecone-cli

# list indexes in this project
./dist/pc_darwin_arm64/pc index list

# show local-keys
./dist/pc_darwin_arm64/pc auth local-keys list

# target a new project, list indexes, and check keys again
./dist/pc_darwin_arm64/pc target --project austin-dev
./dist/pc_darwin_arm64/pc index list
./dist/pc_darwin_arm64/pc auth local-keys list

# test out pruning
./dist/pc_darwin_arm64/pc auth local-keys --prune --skip-confirmation --origin cli

# configure a service account and check you're logged out
./dist/pc_darwin_arm64/pc auth configure --client-id "your-id" --client-secret "your-secret"
./dist/pc_darwin_arm64/pc auth status

# list projects and make sure targeting still works for projects the service account has access to
./dist/pc_darwin_arm64/pc project list
./dist/pc_darwin_arm64/pc target --project my-project

# etc

…y in target command and elsewhere with admin API. implement logic for caching ManagedKeys per-project in Viper, and properly creating keys for projects as needed when instantiating the go SDK for control and data plane operations, implement TokenManager and rename the oauth2 package to auth in utils, refactor some of the cruft around building clients and credentials
…cy for manual randomization for api key suffixes
…, allowing us to pass orgId to keep the targeted org sticky
…ice accounts mutually exclusive and clear the other on configuration, update auth status and add a presenter for printing the information, add TargetCreds and TargetUser to state, add pc auth clear command, fix logical issues with multiple auth paths
…ub-command to auth command, add functionality for listing out managed keys with json and reveal options
…d out functionality for cleaning up API keys that have been stored locally for use with the CLI
… and deleting locally stored keys on a delete operation, adjust printed output for auth local-keys list
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@pinecone-io pinecone-io deleted a comment from claude bot Sep 23, 2025
@austin-denoble austin-denoble marked this pull request as ready for review September 24, 2025 00:12
@claude
Copy link

claude bot commented Sep 24, 2025

Claude finished @austin-denoble's task —— View job


Code Review Completed ✅

I've conducted a comprehensive review of this authentication refactoring PR. Here's my detailed analysis:

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Recommendations

  1. High Priority:

    • Replace ParseUnverified with proper JWT validation or add claim validation
    • Standardize mutex usage patterns across token and secrets management
    • Improve error handling for malformed tokens
  2. Medium Priority:

    • Add retry logic for transient API failures in prune operations
    • Enhance input validation for service account credentials
    • Consider making global API key precedence more explicit in UX
  3. Low Priority:

    • Unify CLI output patterns across all commands
    • Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates strong security awareness, proper concurrency handling, and excellent user experience design. The few issues identified are mostly edge cases and can be addressed in follow-up PRs.

The refactoring successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Well done! 🎉


@claude
Copy link

claude bot commented Sep 24, 2025

Claude finished @austin-denoble's task —— View job


Code Review Completed ✅

I've conducted a comprehensive review of this authentication refactoring PR. Here's my detailed analysis:

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Recommendations

  1. High Priority:

    • Replace ParseUnverified with proper JWT validation or add claim validation
    • Standardize mutex usage patterns across token and secrets management
    • Improve error handling for malformed tokens
  2. Medium Priority:

    • Add retry logic for transient API failures in prune operations
    • Enhance input validation for service account credentials
    • Consider making global API key precedence more explicit in UX
  3. Low Priority:

    • Unify CLI output patterns across all commands
    • Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates strong security awareness, proper concurrency handling, and excellent user experience design. The few issues identified are mostly edge cases and can be addressed in follow-up PRs.

The refactoring successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Well done! 🎉



type MarshaledProperty[T any] struct {
DefaultValue *T
DefaultValue T
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I swapped to a value rather than a pointer here because it was a bit easier to reason about downstream when working with the properties, and also since we're writing to and marshaling out of a file, it didn't seem like we needed to pass a mutable ref around.

name string
forceEncryptionWithCMEK bool
maxPods int
target bool
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

New flag allowing a user to immediately target a newly created project.

@claude
Copy link

claude bot commented Sep 24, 2025

Claude finished @austin-denoble's task —— View job


Claude finished reviewing this PR

Code Review Progress

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Comprehensive Code Review

This is a well-architected authentication refactoring that successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Here's my detailed analysis:

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Test Coverage

Based on the code structure, I don't see comprehensive test coverage for the authentication logic. Consider adding:

  • Unit tests for TokenManager race conditions
  • Integration tests for token refresh scenarios
  • Error simulation tests for API failures
  • Concurrent access tests for ManagedKey storage

Recommendations

High Priority:

  1. Replace ParseUnverified with proper JWT validation or add claim validation
  2. Standardize mutex usage patterns across token and secrets management
  3. Improve error handling for malformed tokens

Medium Priority:

  1. Add retry logic for transient API failures in prune operations
  2. Enhance input validation for service account credentials
  3. Consider making global API key precedence more explicit in UX

Low Priority:

  1. Unify CLI output patterns across all commands
  2. Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates:

  • ✅ Strong security awareness
  • ✅ Proper concurrency handling
  • ✅ Excellent user experience design
  • ✅ Backward compatibility maintenance
  • ✅ Clean separation of concerns

The few issues identified are mostly edge cases and can be addressed in follow-up PRs. The refactoring successfully addresses the original problems while providing a solid foundation for future authentication enhancements.

Recommendation: Approve with minor follow-up improvements 🎉


if access_token.AccessToken == "" {
msg.FailMsg("You must be logged in to set a target context. Run %s to log in.", style.Code("pc login"))
exit.ErrorMsg("You must be logged in to set a target context")
accessToken, err := oauth.Token(cmd.Context())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The bulk of the changes in this file are refactoring around the removal of the dashboard package, and using the Go SDK resources directly.

return orgName
}

type ListModel struct {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I extracted all of this into a reusable utility in the prompt package down in the /utils/ folder. It was generic enough, and could be reused elsewhere.

Comment on lines +13 to +14
var oauth2TokenMu sync.RWMutex
var oAuth2Token = configuration.MarshaledProperty[oauth2.Token]{
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adding a mutex and un-exporting the MarshaledProperty itself.

}

var ApiKey = configuration.ConfigProperty[string]{
var GlobalApiKey = configuration.ConfigProperty[string]{
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I renamed this to "GlobalApiKey" because it acts as a kind of override, and I wanted to distinguish it from locally managed API keys.


// ManagedKey represents an API key that is being actively managed by the CLI
// Either the CLI created it to work with a project, or a user created it and stored it explicitly
type ManagedKey struct {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the shape of the object we store locally to track keys.


func GetProjectAPIKeys() map[string]string {
keys := ProjectAPIKeys.Get()
func GetOAuth2Token() oauth2.Token {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Getter/setter wrappers for things which leverage the mutex.


func SetProjectAPIKey(projectId string, apiKey string) {
keys := ProjectAPIKeys.Get()
func SetProjectManagedKey(managedKey ManagedKey) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My original implementation of this was never being called from the core CLI code, and was also inadequate in terms of what we actually need to store to manage things.


import "github.com/pinecone-io/cli/internal/pkg/utils/pcio"

type TargetOrganization struct {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I moved these in here because they're a part of TargetContext and it felt like it made sense to me. I also added TargetUser which I don't think is being leveraged in a real way, and maybe was unnecessary. (possible TODO)

DashboardUrl string
IndexControlPlaneUrl string
DashboardUrl string
PineconeGCPURL string
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Just a rename to reflect things a bit better.

// Parse token claims to get orgId
accessToken := secrets.OAuth2Token.Get()
claims, err := pc_oauth2.ParseClaimsUnverified(&accessToken)
accessToken, err := oauth.Token(ctx)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The refactoring in this command is to support the new TokenManager plumbing, and remove reliance on dashboard.


// Token is a convenience function that gets the current OAuth2 token for the CLI
// It is a wrapper around the TokenManager.Token method
func Token(ctx context.Context) (*oauth2.Token, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is where all the TokenManager logic lives. I tried my best at a somewhat robust singleton factory, because it felt like trampling token credentials would be a possibility somewhere along the line.

This code also handles all of the token refreshing, so essentially whenever anything calls in for a token, it's refreshed if it needs to be.

"github.com/pinecone-io/cli/internal/pkg/utils/pcio"
)

type ListModel struct {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Interactive list selection utilities.

"github.com/pinecone-io/go-pinecone/v4/pinecone"
)

const (
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are a lot of changes going on in here. This package is how we instantiate the Go SDK, and there's a bunch of logic in here for resolving which credentials we're using for which client. There's an AdminClient for admin API operations which needs either a user token or service account credentials. There's also the regular Client which needs an API key or a token with a Project ID (for X-Project-Id).

The logic for creating a new CLI-managed API key if necessary is here, along with the logic for pulling the map of existing keys to check if we need to create one at all, etc.

@claude
Copy link

claude bot commented Sep 24, 2025

Claude finished @austin-denoble's task —— View job


Claude finished reviewing this PR

Code Review Progress

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Comprehensive Code Review

This is a well-architected authentication refactoring that successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Here's my detailed analysis:

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Test Coverage

Based on the code structure, I don't see comprehensive test coverage for the authentication logic. Consider adding:

  • Unit tests for TokenManager race conditions
  • Integration tests for token refresh scenarios
  • Error simulation tests for API failures
  • Concurrent access tests for ManagedKey storage

Recommendations

High Priority:

  1. Replace ParseUnverified with proper JWT validation or add claim validation
  2. Standardize mutex usage patterns across token and secrets management
  3. Improve error handling for malformed tokens

Medium Priority:

  1. Add retry logic for transient API failures in prune operations
  2. Enhance input validation for service account credentials
  3. Consider making global API key precedence more explicit in UX

Low Priority:

  1. Unify CLI output patterns across all commands
  2. Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates:

  • ✅ Strong security awareness
  • ✅ Proper concurrency handling
  • ✅ Excellent user experience design
  • ✅ Backward compatibility maintenance
  • ✅ Clean separation of concerns

The few issues identified are mostly edge cases and can be addressed in follow-up PRs. The refactoring successfully addresses the original problems while providing a solid foundation for future authentication enhancements.

Recommendation: Approve with minor follow-up improvements 🎉


@claude
Copy link

claude bot commented Sep 26, 2025

Claude finished @austin-denoble's task —— View job


Claude finished reviewing this PR

Code Review Progress

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Comprehensive Code Review

This is a well-architected authentication refactoring that successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Here's my detailed analysis:

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Test Coverage

Based on the code structure, I don't see comprehensive test coverage for the authentication logic. Consider adding:

  • Unit tests for TokenManager race conditions
  • Integration tests for token refresh scenarios
  • Error simulation tests for API failures
  • Concurrent access tests for ManagedKey storage

Recommendations

High Priority:

  1. Replace ParseUnverified with proper JWT validation or add claim validation
  2. Standardize mutex usage patterns across token and secrets management
  3. Improve error handling for malformed tokens

Medium Priority:

  1. Add retry logic for transient API failures in prune operations
  2. Enhance input validation for service account credentials
  3. Consider making global API key precedence more explicit in UX

Low Priority:

  1. Unify CLI output patterns across all commands
  2. Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates:

  • ✅ Strong security awareness
  • ✅ Proper concurrency handling
  • ✅ Excellent user experience design
  • ✅ Backward compatibility maintenance
  • ✅ Clean separation of concerns

The few issues identified are mostly edge cases and can be addressed in follow-up PRs. The refactoring successfully addresses the original problems while providing a solid foundation for future authentication enhancements.

Recommendation: Approve with minor follow-up improvements 🎉


@claude
Copy link

claude bot commented Sep 26, 2025

Claude finished @austin-denoble's task —— View job


Claude finished reviewing this PR

Code Review Progress

  • Analyze authentication architecture and security
  • Review token management and refresh logic
  • Examine concurrent access patterns and thread safety
  • Check credential storage and cleanup mechanisms
  • Review new CLI commands and user experience
  • Assess error handling and edge cases
  • Provide overall feedback and recommendations

Comprehensive Code Review

This is a well-architected authentication refactoring that successfully addresses the original problems (token refresh, dashboard API removal) while maintaining backward compatibility. Here's my detailed analysis:

Security & Architecture

Strong Points

  1. Proper credential isolation - Clear separation between user tokens, service accounts, and API keys with appropriate precedence rules
  2. Thread-safe storage - Excellent use of sync.RWMutex for both OAuth tokens and managed keys in secrets.go:13,38
  3. Secure token refresh - Custom refresh implementation correctly maintains organization context (token.go:120-139)
  4. Cryptographically secure randomness - Proper use of crypto/rand for API key generation (client.go:210)

⚠️ Security Concerns

  1. Unverified JWT parsing (oauth/logging.go:47-59):

    • Using ParseUnverified is dangerous for production code
    • Consider using a proper JWT verification library with signature validation
    • If verification isn't possible, at minimum validate critical claims
  2. Error handling in JWT parsing (oauth/logging.go:56):

    • Calls exit.Error() on parsing failure, which could crash the CLI
    • Should gracefully handle malformed tokens instead of terminating
  3. Credential precedence could be confusing (client.go:44-52):

    • Global API key silently overrides user authentication
    • Warning message helps but users might miss it

Token Management & Concurrency

Excellent Implementation

  1. TokenManager singleton pattern (token.go:38-42) - Proper use of sync.Once prevents race conditions
  2. Prefetch window (token.go:17,80) - Smart 90-second refresh buffer prevents token expiry issues
  3. Atomic persistence logic (token.go:97-98) - Only saves tokens when changed

⚠️ Potential Issues

  1. Mixed synchronization approaches:

    • TokenManager uses sync.Mutex (token.go:34)
    • Secrets uses sync.RWMutex (secrets.go:13)
    • Could lead to deadlocks if both are held simultaneously
  2. Token clearing race condition (token.go:104-108):

    • ClearToken() only clears in-memory token, not persistent storage
    • Inconsistent with how tokens are managed elsewhere

API Key Management

Robust Design

  1. ManagedKey concept is well-architected with proper origin tracking (secrets.go:145-161)
  2. Automatic key creation with fallback logic (client.go:155-193)
  3. Comprehensive cleanup commands with dry-run and confirmation (local_keys_prune.go)

⚠️ Edge Cases

  1. Orphaned key handling (local_keys_prune.go:70-81):

    • If API call fails, continues to next project but could leave inconsistent state
    • Should batch failures and report them to user
  2. Key name collision (client.go:222-229):

    • Fallback to "000000" if randomization fails
    • Could cause conflicts if multiple CLI instances hit this edge case simultaneously

Error Handling & User Experience

Good Practices

  1. Rich status command (status.go) provides excellent debugging information
  2. Interactive project selection (configure.go:249-275) with proper exit handling
  3. Clear error messages with actionable suggestions throughout

⚠️ Areas for Improvement

  1. Input validation (configure.go:76-78):

    • strings.TrimSpace() helps but doesn't validate format
    • Should validate client ID/secret formats if there are requirements
  2. Confirmation prompt (local_keys_prune.go:152-178):

    • Uses fmt.Print instead of proper CLI output patterns
    • Could be inconsistent with rest of CLI styling

Performance Considerations

  • Minimal impact: Token caching and selective API calls are well-implemented
  • Network efficiency: Proper use of refresh tokens reduces authentication overhead
  • Memory usage: Reasonable for CLI application scope

Test Coverage

Based on the code structure, I don't see comprehensive test coverage for the authentication logic. Consider adding:

  • Unit tests for TokenManager race conditions
  • Integration tests for token refresh scenarios
  • Error simulation tests for API failures
  • Concurrent access tests for ManagedKey storage

Recommendations

High Priority:

  1. Replace ParseUnverified with proper JWT validation or add claim validation
  2. Standardize mutex usage patterns across token and secrets management
  3. Improve error handling for malformed tokens

Medium Priority:

  1. Add retry logic for transient API failures in prune operations
  2. Enhance input validation for service account credentials
  3. Consider making global API key precedence more explicit in UX

Low Priority:

  1. Unify CLI output patterns across all commands
  2. Add more comprehensive logging for debugging auth flows

Overall Assessment

This is a high-quality implementation that significantly improves the CLI's authentication architecture. The code demonstrates:

  • ✅ Strong security awareness
  • ✅ Proper concurrency handling
  • ✅ Excellent user experience design
  • ✅ Backward compatibility maintenance
  • ✅ Clean separation of concerns

The few issues identified are mostly edge cases and can be addressed in follow-up PRs. The refactoring successfully addresses the original problems while providing a solid foundation for future authentication enhancements.

Recommendation: Approve with minor follow-up improvements 🎉


@austin-denoble austin-denoble merged commit f136d97 into main Sep 26, 2025
5 checks passed
@austin-denoble austin-denoble deleted the adenoble/implement-credentials-logic branch September 26, 2025 06:55
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