feat(auth): add OAuth2 grant-type packages with keychain token caching - #91
Conversation
…, device_code, and client_credentials grant types and keychain token caching
henryrecker-pingidentity
left a comment
There was a problem hiding this comment.
Some minor comments
| // Configuration represents the OAuth2 authentication configuration for the PingFederate Go | ||
| // Client SDK. It holds the runtime endpoint and the credentials for the configured grant type, | ||
| // and produces an oauth2.TokenSource via TokenSource. Populate it using the builder methods (With...). | ||
| type Configuration struct { |
There was a problem hiding this comment.
We now have two separate configuration objects in the client - see configurationapi/configuration.go
We need to consolidate and avoid having two separate ways to build a client
| // calls. It returns the client along with a context carrying the token source | ||
| // (configurationapi.ContextOAuth2) so callers can pass the returned context directly to generated | ||
| // API methods, without separately constructing and wiring a configurationapi.Configuration. | ||
| func (c *Configuration) NewAPIClient(ctx context.Context, adminAPIURL string, httpClient *http.Client) (*configurationapi.APIClient, context.Context, error) { |
There was a problem hiding this comment.
This pattern seems too different from what we've established with our clients.
Compare to pingone-go-client's structure - you create a Configuration, pass it into NewAPIClient, and then you can just use that client directly. Here we're expecting the user to pass around this auth context everywhere on their own.
There was a problem hiding this comment.
@wesleymccollam To clarify on the latest changes, the examples for auth code and device code still have the user inserting an http client into the context, while also passing it in to the call to create the API client.
Currently you just directly set the HTTPClient field on the configuration struct - https://github.com/pingidentity/terraform-provider-pingfederate/blob/7d619e09230fde0571455bb4277ad72acd5369f4/internal/provider/provider.go#L688
Can we unify these, or update the examples to the expected pattern? It just seems a little all over the place.
…f a separate auth context
…t's no longer needed twice
Summary
Adds OAuth2 support to the PingFederate Go client so callers can obtain an
oauth2.TokenSourcefor the PingFederate admin API using any of three grant types, with automatic token caching in the OS keychain.config/— high-level, fluentConfigurationbuilder that derives OAuth2 endpoints from the runtime base URL and wires up each grant flow (authorization_codewith PKCE,device_codeper RFC 8628, andclient_credentials), including the loopback-redirect handling and HTML auth-result page for the browser flow.oauth2/— grant-type enum, token-endpoint auth methods, endpoint derivation, and a keychain-backedTokenStorageimplementation so tokens persist and silently refresh across runs.utils/browser/— cross-platform browser launcher for the authorization_code flow.examples/— runnable end-to-end examples for all three grant types, each demonstrating how to inject a custom HTTP client into the token exchange and call the admin API.The HTTP client used for the token exchange is injected via
oauth2.HTTPClienton the context, so callers control TLS/transport for both the token flow and the admin API client.Scope / compatibility
go.mod/go.sum(new dependencies) and a newREADME/Makefile/CONTRIBUTINGare touched among existing files; no changes to the generatedconfigurationapipackage.v1300module line.Testing
config/,oauth2/, andutils/browser/pass;gofmt/go vetclean;go mod tidyis a no-op.devchecknotestpasses clean (build, generate, golangci-lint, tfproviderlint, tflint, terrafmt, impi, vet).