Repository: cloudflare/cloudflare-go
Pull request #1981 (2024-05-09 20:51:10)

AUTH-6071 Add various features to Access OIDC SaaS applications
Adds refresh token, custom claims, and pkce without client secret support to cloudflare-go

## Description

docs: https://developers.cloudflare.com/api/operations/access-applications-list-access-applications

## Has your change been tested?

unit tests

## Screenshots (if appropriate):

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
- [ ] This change is using publicly documented in [cloudflare/api-schemas](https://github.com/cloudflare/api-schemas) 
      and relies on stable APIs.

[1]: https://help.github.com/articles/closing-issues-using-keywords/


github-actions[bot]: changelog detected :white_check_mark:

Patch:
diff --git a/.changelog/1981.txt b/.changelog/1981.txt
new file mode 100644
index 000000000..ba98d7203
--- /dev/null
+++ b/.changelog/1981.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+Add Refresh Token, Custom Claims, and PKCE Without Client Secret support to Access OIDC SaaS Applications
+```
diff --git a/access_application.go b/access_application.go
index b99f863f9..75ef4f31c 100644
--- a/access_application.go
+++ b/access_application.go
@@ -199,6 +199,17 @@ type SAMLAttributeConfig struct {
 	Source       SourceConfig `json:"source"`
 }
 
+type OIDCClaimConfig struct {
+	Name     string       `json:"name,omitempty"`
+	Source   SourceConfig `json:"source"`
+	Required *bool        `json:"required,omitempty"`
+	Scope    string       `json:"scope,omitempty"`
+}
+
+type RefreshTokenOptions struct {
+	Lifetime string `json:"lifetime,omitempty"`
+}
+
 type SaasApplication struct {
 	// Items common to both SAML and OIDC
 	AppID     string     `json:"app_id,omitempty"`
@@ -219,13 +230,16 @@ type SaasApplication struct {
 	SamlAttributeTransformJsonata string                `json:"saml_attribute_transform_jsonata"`
 
 	// OIDC saas app
-	ClientID         string   `json:"client_id,omitempty"`
-	ClientSecret     string   `json:"client_secret,omitempty"`
-	RedirectURIs     []string `json:"redirect_uris,omitempty"`
-	GrantTypes       []string `json:"grant_types,omitempty"`
-	Scopes           []string `json:"scopes,omitempty"`
-	AppLauncherURL   string   `json:"app_launcher_url,omitempty"`
-	GroupFilterRegex string   `json:"group_filter_regex,omitempty"`
+	ClientID                     string               `json:"client_id,omitempty"`
+	ClientSecret                 string               `json:"client_secret,omitempty"`
+	RedirectURIs                 []string             `json:"redirect_uris,omitempty"`
+	GrantTypes                   []string             `json:"grant_types,omitempty"`
+	Scopes                       []string             `json:"scopes,omitempty"`
+	AppLauncherURL               string               `json:"app_launcher_url,omitempty"`
+	GroupFilterRegex             string               `json:"group_filter_regex,omitempty"`
+	CustomClaims                 []OIDCClaimConfig    `json:"custom_claims,omitempty"`
+	AllowPKCEWithoutClientSecret *bool                `json:"allow_pkce_without_client_secret,omitempty"`
+	RefreshTokenOptions          *RefreshTokenOptions `json:"refresh_token_options,omitempty"`
 }
 
 type AccessAppLauncherCustomization struct {


Test patch:
diff --git a/access_application_test.go b/access_application_test.go
index 11187ebb9..086479c95 100644
--- a/access_application_test.go
+++ b/access_application_test.go
@@ -1115,7 +1115,18 @@ func TestCreateOIDCSaasAccessApplications(t *testing.T) {
 					"grant_types": ["authorization_code"],
 					"scopes": ["openid", "email", "profile", "groups"],
 					"app_launcher_url": "https://saas.example.com",
-					"group_filter_regex": ".*"
+					"group_filter_regex": ".*",
+					"allow_pkce_without_client_secret": false,
+					"custom_claims": [
+						{
+							"name": "test1",
+							"source": {
+								"name": "test1"
+							},
+							"required": true,
+							"scope": "profile"
+						}
+					]
 				}
 			}
 		}
@@ -1141,14 +1152,23 @@ func TestCreateOIDCSaasAccessApplications(t *testing.T) {
 		LogoURL:                "https://www.example.com/example.png",
 		SkipInterstitial:       BoolPtr(true),
 		SaasApplication: &SaasApplication{
-			AuthType:         "oidc",
-			ClientID:         "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893",
-			ClientSecret:     "secret",
-			RedirectURIs:     []string{"https://saas.example.com"},
-			GrantTypes:       []string{"authorization_code"},
-			Scopes:           []string{"openid", "email", "profile", "groups"},
-			AppLauncherURL:   "https://saas.example.com",
-			GroupFilterRegex: ".*",
+			AuthType:                     "oidc",
+			ClientID:                     "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893",
+			ClientSecret:                 "secret",
+			RedirectURIs:                 []string{"https://saas.example.com"},
+			GrantTypes:                   []string{"authorization_code"},
+			Scopes:                       []string{"openid", "email", "profile", "groups"},
+			AppLauncherURL:               "https://saas.example.com",
+			GroupFilterRegex:             ".*",
+			AllowPKCEWithoutClientSecret: BoolPtr(false),
+			CustomClaims: []OIDCClaimConfig{
+				{
+					Name:     "test1",
+					Source:   SourceConfig{Name: "test1"},
+					Required: BoolPtr(true),
+					Scope:    "profile",
+				},
+			},
 		},
 		CreatedAt:                &createdAt,
 		UpdatedAt:                &updatedAt,
@@ -1161,10 +1181,19 @@ func TestCreateOIDCSaasAccessApplications(t *testing.T) {
 	actual, err := client.CreateAccessApplication(context.Background(), AccountIdentifier(testAccountID), CreateAccessApplicationParams{
 		Name: "Admin Saas Site",
 		SaasApplication: &SaasApplication{
-			AuthType:         "oidc",
-			RedirectURIs:     []string{"https://saas.example.com"},
-			AppLauncherURL:   "https://saas.example.com",
-			GroupFilterRegex: ".*",
+			AuthType:                     "oidc",
+			RedirectURIs:                 []string{"https://saas.example.com"},
+			AppLauncherURL:               "https://saas.example.com",
+			GroupFilterRegex:             ".*",
+			AllowPKCEWithoutClientSecret: BoolPtr(false),
+			CustomClaims: []OIDCClaimConfig{
+				{
+					Name:     "test1",
+					Source:   SourceConfig{Name: "test1"},
+					Required: BoolPtr(true),
+					Scope:    "profile",
+				},
+			},
 		},
 		SessionDuration: "24h",
 	})
@@ -1178,10 +1207,19 @@ func TestCreateOIDCSaasAccessApplications(t *testing.T) {
 	actual, err = client.CreateAccessApplication(context.Background(), ZoneIdentifier(testZoneID), CreateAccessApplicationParams{
 		Name: "Admin Saas Site",
 		SaasApplication: &SaasApplication{
-			AuthType:         "oidc",
-			RedirectURIs:     []string{"https://saas.example.com"},
-			AppLauncherURL:   "https://saas.example.com",
-			GroupFilterRegex: ".*",
+			AuthType:                     "oidc",
+			RedirectURIs:                 []string{"https://saas.example.com"},
+			AppLauncherURL:               "https://saas.example.com",
+			GroupFilterRegex:             ".*",
+			AllowPKCEWithoutClientSecret: BoolPtr(false),
+			CustomClaims: []OIDCClaimConfig{
+				{
+					Name:     "test1",
+					Source:   SourceConfig{Name: "test1"},
+					Required: BoolPtr(true),
+					Scope:    "profile",
+				},
+			},
 		},
 		SessionDuration: "24h",
 	})