Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The PingOne Terraform provider is a plugin for [Terraform](https://www.terraform

Extended documentation can be found at:
* [Terraform Registry](https://registry.terraform.io/providers/pingidentity/pingone/latest/docs)
* [Using PingCLI with the Provider](./docs/guides/pingcli-authentication.md)
* [PingOne API and Developer Documentation](https://apidocs.pingidentity.com/pingone/platform/v1/api/)
* [Introduction to PingOne](https://docs.pingidentity.com/bundle/pingone/page/als1564020488261.html)
* [Ping Identity Developer Portal](https://developer.pingidentity.com/en.html)
Expand Down
132 changes: 132 additions & 0 deletions docs/guides/pingcli-authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
layout: ""
page_title: "Using PingCLI with the Provider"
description: |-
Configure the PingOne Terraform provider to authenticate using PingCLI profiles and stored tokens.
---

# Using PingCLI with the Provider

The PingOne Terraform provider can authenticate using credentials and tokens managed by [PingCLI](https://github.com/pingidentity/pingcli). This allows you to log in once with PingCLI and have Terraform automatically discover and use the stored token or client credentials from your PingCLI profile.

## Overview

- Run `pingcli login` with your preferred grant type.
- Ensure your PingCLI config’s `authentication.type` matches the grant.
- Point the Terraform provider to the PingCLI config file and profile via `config_path` and `config_profile` (or the env vars `PINGCLI_CONFIG` and `PINGCLI_PROFILE`).

## Step 1: Log in with PingCLI

Choose a grant type and profile name (e.g., `dev`). This writes a token to secure storage (macOS Keychain by default) and optionally to `~/.pingcli/credentials` if file storage is enabled.

```sh
# Authorization Code flow (interactive)
pingcli login --type authorization_code --profile dev

# Device Code flow (interactive, alternative to auth code)
pingcli login --type device_code --profile dev

# Client Credentials flow (non-interactive)
pingcli login --type client_credentials --profile dev
```

## Step 2: Verify your PingCLI configuration

The provider reads the PingCLI config to resolve region, environment ID, auth type, and (for some flows) client credentials. A minimal example for the `authorization_code` grant type:

```yaml
activeProfile: dev

dev:
service:
pingOne:
regionCode: NA
authentication:
type: authorization_code
environmentID: 11111111-1111-1111-1111-111111111111
authorizationCode:
clientID: 22222222-2222-2222-2222-222222222222
# Optional fields if you prefer custom redirect params:
# redirectURIPath: /callback
# redirectURIPort: "3000"
```

Other grant type snippets:

Device Code:
```yaml
dev:
service:
pingOne:
regionCode: NA
authentication:
type: device_code
environmentID: 11111111-1111-1111-1111-111111111111
deviceCode:
clientID: 22222222-2222-2222-2222-222222222222
```

Client Credentials:
```yaml
cc:
service:
pingOne:
regionCode: NA
authentication:
type: client_credentials
environmentID: 11111111-1111-1111-1111-111111111111
clientCredentials:
clientID: 22222222-2222-2222-2222-222222222222
clientSecret: ${CLIENT_SECRET}
```

Worker (alias of client credentials):
```yaml
worker:
service:
pingOne:
regionCode: NA
authentication:
type: worker
worker:
environmentID: 11111111-1111-1111-1111-111111111111
clientID: 22222222-2222-2222-2222-222222222222
clientSecret: ${CLIENT_SECRET}
```

## Step 3: Point the provider at your PingCLI profile

You can configure this in Terraform:

```hcl
provider "pingone" {
config_path = "~/.pingcli/config.yaml"
config_profile = "dev"
}
```

Or via environment variables:

```sh
export PINGCLI_CONFIG="~/.pingcli/config.yaml"
export PINGCLI_PROFILE="dev"
```

## Behavior and Fallbacks

When `config_path` is set, the provider resolves credentials in this order:

1. Use a valid stored token from PingCLI (Keychain or `~/.pingcli/credentials`).
2. If no stored token is found and `api_access_token` is set in the provider, use that token.
3. If the PingCLI profile contains client credentials (`client_credentials` or `worker`) and an environment ID, use those to obtain a token.
4. If none of the above apply, the provider returns an error and prompts you to run `pingcli login`.

Region resolution:
- If using a stored token, the region is taken from the PingCLI profile (`regionCode`).
- If using `api_access_token` or provider-supplied credentials, `region_code` in the provider (or `PINGONE_REGION_CODE`) can be used to select endpoints. When both are present, the provider value takes precedence.

## FAQ

- Do I need to run `pingcli login` for client credentials? For non-interactive flows, you can either run `pingcli login --type client_credentials` or specify the client credentials directly in the PingCLI config. The provider will use them if no stored token is found.
- Where does PingCLI store tokens? On macOS, tokens are persisted in the Keychain. If file storage is enabled, it also writes to `~/.pingcli/credentials`.
- Can I still use `client_id`, `client_secret`, and `environment_id` in the provider? Yes, but not together with `config_path`. For pingcli-based auth, prefer `config_path` and `config_profile`.
51 changes: 51 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,55 @@ For code examples showing how to configure the PingOne service using Terraform,

## Provider Authentication

### Authenticate using PingCLI profile (stored token)

You can use a saved token from [PingCLI](https://github.com/pingidentity/pingcli) instead of managing client credentials directly in Terraform. This is convenient for interactive users and CI environments that already run `pingcli login`.

1) Use PingCLI to log in with your preferred grant type and profile (e.g., `authorization_code`, `device_code`, or `client_credentials`). Ensure the profile’s `authentication.type` in the PingCLI config matches the grant you used.

```shell
pingcli login --type authorization_code --profile dev
# or
pingcli login --type device_code --profile dev
# or
pingcli login --type client_credentials --profile dev
```

2) In Terraform, point the provider to your PingCLI config file and profile:

```terraform
terraform {
required_providers {
pingone = {
source = "pingidentity/pingone"
version = ">= 1.13, < 1.14"
}
}
}

provider "pingone" {
# Path to your PingCLI config file and profile name
config_path = "~/.pingcli/config.yaml"
config_profile = "dev"
}
```

Alternatively, you can set environment variables:

```shell
export PINGCLI_CONFIG="~/.pingcli/config.yaml"
export PINGCLI_PROFILE="dev"
terraform plan
```

Notes:
- The provider will first try to use a valid stored token from PingCLI (Keychain or `~/.pingcli/credentials`).
- If no stored token is found and `api_access_token` is set on the provider, it uses that token.
- If the PingCLI profile contains `client_credentials` (client ID/secret) and environment ID, the provider can use them to obtain a token.
- Otherwise, the provider returns an error prompting you to run `pingcli login`.

For full details and examples of the PingCLI config structure, see the guide: [Using PingCLI with the Provider](./guides/pingcli-authentication.md).

### Authenticate using static OAuth 2.0 Client Credentials (PingOne Worker Application)

```terraform
Expand Down Expand Up @@ -147,6 +196,8 @@ provider "pingone" {
- `region_code` (String) The PingOne region to use, which selects the appropriate service endpoints. Options are `AP` (for Asia-Pacific `.asia` tenants), `AU` (for Asia-Pacific `.com.au` tenants), `CA` (for Canada `.ca` tenants), `EU` (for Europe `.eu` tenants), `NA` (for North America `.com` tenants) and `SG` (for Singapore `.sg` tenants). Default value can be set with the `PINGONE_REGION_CODE` environment variable.
- `service_endpoints` (Block List) A single block containing configuration items to override the service API endpoints of PingOne. (see [below for nested schema](#nestedblock--service_endpoints))
- `append_user_agent` (String) A custom string value to append to the end of the `User-Agent` header when making API requests to the PingOne service. Default value can be set with the `PINGONE_TF_APPEND_USER_AGENT` environment variable.
- `config_path` (String) Path to a PingCLI configuration file containing authentication credentials. Default value can be set with the `PINGCLI_CONFIG` environment variable. Cannot be used together with `client_id`, `client_secret`, `environment_id`, or `api_access_token`. If set, `config_profile` can optionally specify which profile to use (defaults to the active profile in the config file).
- `config_profile` (String) Name of the profile to use from the PingCLI configuration file. If not specified, uses the active profile defined in the config file. Default value can be set with the `PINGCLI_PROFILE` environment variable. Requires `config_path` to be set.

<a id="nestedblock--global_options"></a>
### Nested Schema for `global_options`
Expand Down
21 changes: 18 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/hashicorp/terraform-plugin-mux v0.21.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1
github.com/hashicorp/terraform-plugin-testing v1.13.3
github.com/knadh/koanf/v2 v2.3.0
github.com/mitchellh/mapstructure v1.5.0
github.com/patrickcping/pingone-go-sdk-v2 v0.14.0
github.com/patrickcping/pingone-go-sdk-v2/authorize v0.8.2
Expand All @@ -38,6 +39,7 @@ require (
require (
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
4d63.com/gochecknoglobals v0.2.2 // indirect
al.essio.dev/pkg/shellescape v1.5.1 // indirect
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go v0.118.3 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
Expand Down Expand Up @@ -102,6 +104,7 @@ require (
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/daixiang0/gci v0.13.5 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
Expand All @@ -113,7 +116,7 @@ require (
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.9 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
Expand Down Expand Up @@ -144,6 +147,7 @@ require (
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
Expand Down Expand Up @@ -201,6 +205,7 @@ require (
github.com/kisielk/gotool v1.0.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/lasiar/canonicalheader v1.1.2 // indirect
Expand Down Expand Up @@ -286,7 +291,7 @@ require (
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdakkota/asciicheck v0.4.1 // indirect
github.com/terraform-linters/tflint v0.57.0 // indirect
Expand Down Expand Up @@ -314,6 +319,7 @@ require (
github.com/ykadowak/zerologlint v0.1.5 // indirect
github.com/yuin/goldmark v1.7.7 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zalando/go-keyring v0.2.6 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
github.com/zeebo/errs v1.4.0 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
Expand All @@ -333,6 +339,7 @@ require (
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v3 v3.0.3 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
golang.org/x/sync v0.17.0 // indirect
Expand Down Expand Up @@ -378,6 +385,8 @@ require (
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/knadh/koanf/parsers/yaml v1.1.0
github.com/knadh/koanf/providers/file v1.2.0
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
Expand All @@ -392,11 +401,17 @@ require (
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/mod v0.27.0 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/oauth2 v0.33.0
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
google.golang.org/grpc v1.75.1 // indirect
google.golang.org/protobuf v1.36.9 // indirect
)

// Use local development version of pingone-go-client with keychain support
replace github.com/pingidentity/pingone-go-client => ../pingone-go-client

// Use local development version of pingone-go-sdk-v2 with debug validation
replace github.com/patrickcping/pingone-go-sdk-v2 => ../pingone-go-sdk-v2
Loading