From 94130a2c64953354e40479e75cd5157f92bfc2e7 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:23:30 +0530 Subject: [PATCH 1/8] feat(docs): Update API creation and update documentation - docs/auth0_apis_create.md: Add subject-type-authorization flag example - docs/auth0_apis_update.md: Add subject-type-authorization flag example feat(cli): Enhance API command with subject type authorization - internal/cli/apis.go: Add subject type authorization handling in create and update commands feat(display): Display subject type authorization in API view - internal/display/apis.go: Include subject type authorization in API view output chore(go): Update go-auth0 dependency to latest version - go.mod: Bump go-auth0 from v1.25.0 to v1.26.1 - go.sum: Update go-auth0 checksum --- docs/auth0_apis_create.md | 18 +++--- docs/auth0_apis_update.md | 16 ++--- go.mod | 2 +- go.sum | 4 +- internal/cli/apis.go | 128 +++++++++++++++++++++++++++++++++----- internal/display/apis.go | 50 ++++++++++----- 6 files changed, 170 insertions(+), 48 deletions(-) diff --git a/docs/auth0_apis_create.md b/docs/auth0_apis_create.md index 14b8e3e62..251bc9537 100644 --- a/docs/auth0_apis_create.md +++ b/docs/auth0_apis_create.md @@ -28,20 +28,22 @@ auth0 apis create [flags] auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256" auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact + auth0 apis create --name myapi --identifier http://my-api --subject-type-authorization '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}' ``` ## Flags ``` - -i, --identifier string Identifier of the API. Cannot be changed once set. - --json Output in json format. - --json-compact Output in compact json format. - -n, --name string Name of the API. - -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). - -s, --scopes strings Comma-separated list of scopes (permissions). - --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") - -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). + -i, --identifier string Identifier of the API. Cannot be changed once set. + --json Output in json format. + --json-compact Output in compact json format. + -n, --name string Name of the API. + -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). + -s, --scopes strings Comma-separated list of scopes (permissions). + --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") + --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). ``` diff --git a/docs/auth0_apis_update.md b/docs/auth0_apis_update.md index 334bc6a53..538da6e00 100644 --- a/docs/auth0_apis_update.md +++ b/docs/auth0_apis_update.md @@ -27,19 +27,21 @@ auth0 apis update [flags] auth0 apis update --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256" auth0 apis update -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json auth0 apis update -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact + auth0 apis update --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' ``` ## Flags ``` - --json Output in json format. - --json-compact Output in compact json format. - -n, --name string Name of the API. - -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). - -s, --scopes strings Comma-separated list of scopes (permissions). - --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") - -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). + --json Output in json format. + --json-compact Output in compact json format. + -n, --name string Name of the API. + -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). + -s, --scopes strings Comma-separated list of scopes (permissions). + --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") + --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). ``` diff --git a/go.mod b/go.mod index b3dd5eb52..06ae88837 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 github.com/atotto/clipboard v0.1.4 - github.com/auth0/go-auth0 v1.25.0 + github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v0.10.0 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e diff --git a/go.sum b/go.sum index 731b525f5..cc3aaf45a 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/auth0/go-auth0 v1.25.0 h1:fNlbDL8CPA+w3mfuuGD12cHjtEK/EDLJAc20xrL1+Eg= -github.com/auth0/go-auth0 v1.25.0/go.mod h1:g9S/4ImupKFx1gSLqeQO0v1yV91Oo5J5bYobLCAL+J4= +github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0 h1:DuuXNV1roDiC7Kh6TjnQE3KIiP2hUor31DtmPgaihwI= +github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0/go.mod h1:g9S/4ImupKFx1gSLqeQO0v1yV91Oo5J5bYobLCAL+J4= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= diff --git a/internal/cli/apis.go b/internal/cli/apis.go index 9d0c9a29a..ce17f37b8 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -2,10 +2,12 @@ package cli import ( "context" + "encoding/json" "errors" "fmt" "net/url" "strconv" + "strings" "github.com/auth0/go-auth0" "github.com/auth0/go-auth0/management" @@ -17,6 +19,13 @@ import ( const apiDefaultTokenLifetime = 86400 +// Subject Type Authorization Policy Constants. +const ( + subjectTypePolicyAllowAll = "allow_all" + subjectTypePolicyDenyAll = "deny_all" + subjectTypePolicyRequireClientGrant = "require_client_grant" +) + var ( apiID = Argument{ Name: "Id", @@ -68,6 +77,11 @@ var ( ShortForm: "n", Help: "Number of APIs to retrieve. Minimum 1, maximum 1000.", } + apiSubjectTypeAuthorization = Flag{ + Name: "Subject Type Authorization", + LongForm: "subject-type-authorization", + Help: "JSON object defining access policies for user and client flows. Example: '{\"user\":{\"policy\":\"require_client_grant\"},\"client\":{\"policy\":\"deny_all\"}}'", + } ) func apisCmd(cli *cli) *cobra.Command { @@ -214,12 +228,13 @@ func showAPICmd(cli *cli) *cobra.Command { func createAPICmd(cli *cli) *cobra.Command { var inputs struct { - Name string - Identifier string - Scopes []string - TokenLifetime int - AllowOfflineAccess bool - SigningAlgorithm string + Name string + Identifier string + Scopes []string + TokenLifetime int + AllowOfflineAccess bool + SigningAlgorithm string + SubjectTypeAuthorization string } cmd := &cobra.Command{ @@ -238,7 +253,8 @@ func createAPICmd(cli *cli) *cobra.Command { auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256" auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json - auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact`, + auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact + auth0 apis create --name myapi --identifier http://my-api --subject-type-authorization '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}'`, RunE: func(cmd *cobra.Command, args []string) error { if err := apiName.Ask(cmd, &inputs.Name, nil); err != nil { return err @@ -265,6 +281,10 @@ func createAPICmd(cli *cli) *cobra.Command { return err } + if err := apiSubjectTypeAuthorization.Ask(cmd, &inputs.SubjectTypeAuthorization, nil); err != nil { + return err + } + api := &management.ResourceServer{ Name: &inputs.Name, Identifier: &inputs.Identifier, @@ -283,6 +303,14 @@ func createAPICmd(cli *cli) *cobra.Command { api.TokenLifetime = auth0.Int(inputs.TokenLifetime) } + if len(inputs.SubjectTypeAuthorization) > 0 { + subjectTypeAuth, err := parseSubjectTypeAuthorization(inputs.SubjectTypeAuthorization) + if err != nil { + return err + } + api.SubjectTypeAuthorization = subjectTypeAuth + } + if err := ansi.Waiting(func() error { return cli.api.ResourceServer.Create(cmd.Context(), api) }); err != nil { @@ -308,18 +336,20 @@ func createAPICmd(cli *cli) *cobra.Command { apiOfflineAccess.RegisterBool(cmd, &inputs.AllowOfflineAccess, false) apiTokenLifetime.RegisterInt(cmd, &inputs.TokenLifetime, 0) apiSigningAlgorithm.RegisterString(cmd, &inputs.SigningAlgorithm, "RS256") + apiSubjectTypeAuthorization.RegisterString(cmd, &inputs.SubjectTypeAuthorization, "") return cmd } func updateAPICmd(cli *cli) *cobra.Command { var inputs struct { - ID string - Name string - Scopes []string - TokenLifetime int - AllowOfflineAccess bool - SigningAlgorithm string + ID string + Name string + Scopes []string + TokenLifetime int + AllowOfflineAccess bool + SigningAlgorithm string + SubjectTypeAuthorization string } cmd := &cobra.Command{ @@ -337,7 +367,8 @@ func updateAPICmd(cli *cli) *cobra.Command { auth0 apis update --name myapi --token-lifetime 6100 --offline-access=false auth0 apis update --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256" auth0 apis update -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json - auth0 apis update -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact`, + auth0 apis update -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact + auth0 apis update --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}'`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { if err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions); err != nil { @@ -380,6 +411,18 @@ func updateAPICmd(cli *cli) *cobra.Command { return err } + // Current subject type authorization value for display. + var currentSubjectTypeJSON string + if current.SubjectTypeAuthorization != nil { + if jsonBytes, err := json.Marshal(current.SubjectTypeAuthorization); err == nil { + currentSubjectTypeJSON = string(jsonBytes) + } + } + + if err := apiSubjectTypeAuthorization.AskU(cmd, &inputs.SubjectTypeAuthorization, ¤tSubjectTypeJSON); err != nil { + return err + } + api := &management.ResourceServer{ AllowOfflineAccess: &inputs.AllowOfflineAccess, } @@ -404,6 +447,15 @@ func updateAPICmd(cli *cli) *cobra.Command { api.SigningAlgorithm = &inputs.SigningAlgorithm } + api.SubjectTypeAuthorization = current.SubjectTypeAuthorization + if inputs.SubjectTypeAuthorization != "" { + subjectTypeAuth, err := parseSubjectTypeAuthorization(inputs.SubjectTypeAuthorization) + if err != nil { + return err + } + api.SubjectTypeAuthorization = subjectTypeAuth + } + if err := ansi.Waiting(func() error { return cli.api.ResourceServer.Update(cmd.Context(), current.GetID(), api) }); err != nil { @@ -423,6 +475,7 @@ func updateAPICmd(cli *cli) *cobra.Command { apiOfflineAccess.RegisterBoolU(cmd, &inputs.AllowOfflineAccess, false) apiTokenLifetime.RegisterIntU(cmd, &inputs.TokenLifetime, 0) apiSigningAlgorithm.RegisterStringU(cmd, &inputs.SigningAlgorithm, "RS256") + apiSubjectTypeAuthorization.RegisterStringU(cmd, &inputs.SubjectTypeAuthorization, "") return cmd } @@ -625,3 +678,50 @@ func (c *cli) filteredAPIPickerOptions(ctx context.Context, include func(r *mana return opts, nil } + +func parseSubjectTypeAuthorization(jsonStr string) (*management.ResourceServerSubjectTypeAuthorization, error) { + if jsonStr == "" { + return nil, nil + } + + var result management.ResourceServerSubjectTypeAuthorization + if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { + return nil, fmt.Errorf("invalid JSON for subject type authorization: %w", err) + } + + // Define valid policies for each flow type. + validUserPolicies := []string{subjectTypePolicyAllowAll, subjectTypePolicyDenyAll, subjectTypePolicyRequireClientGrant} + validClientPolicies := []string{subjectTypePolicyDenyAll, subjectTypePolicyRequireClientGrant} + + // Validate user policy. + if result.User != nil && result.User.Policy != nil { + userPolicy := *result.User.Policy + isValid := false + for _, valid := range validUserPolicies { + if userPolicy == valid { + isValid = true + break + } + } + if !isValid { + return nil, fmt.Errorf("invalid user policy: %s. Valid options: %s", userPolicy, strings.Join(validUserPolicies, ", ")) + } + } + + // Validate client policy. + if result.Client != nil && result.Client.Policy != nil { + clientPolicy := *result.Client.Policy + isValid := false + for _, valid := range validClientPolicies { + if clientPolicy == valid { + isValid = true + break + } + } + if !isValid { + return nil, fmt.Errorf("invalid client policy: %s. Valid options: %s", clientPolicy, strings.Join(validClientPolicies, ", ")) + } + } + + return &result, nil +} diff --git a/internal/display/apis.go b/internal/display/apis.go index 25177bd89..ef2f501de 100644 --- a/internal/display/apis.go +++ b/internal/display/apis.go @@ -1,6 +1,7 @@ package display import ( + "encoding/json" "fmt" "strconv" "strings" @@ -13,13 +14,14 @@ import ( ) type apiView struct { - ID string - Name string - Identifier string - Scopes string - TokenLifetime int - OfflineAccess string - SigningAlgorithm string + ID string + Name string + Identifier string + Scopes string + TokenLifetime int + OfflineAccess string + SigningAlgorithm string + SubjectTypeAuthJSON string raw interface{} } @@ -33,7 +35,7 @@ func (v *apiView) AsTableRow() []string { } func (v *apiView) KeyValues() [][]string { - return [][]string{ + kvs := [][]string{ {"ID", ansi.Faint(v.ID)}, {"NAME", v.Name}, {"IDENTIFIER", v.Identifier}, @@ -42,6 +44,12 @@ func (v *apiView) KeyValues() [][]string { {"ALLOW OFFLINE ACCESS", v.OfflineAccess}, {"SIGNING ALGORITHM", v.SigningAlgorithm}, } + + if len(v.SubjectTypeAuthJSON) > 0 { + kvs = append(kvs, []string{"SUBJECT TYPE AUTHORIZATION", v.SubjectTypeAuthJSON}) + } + + return kvs } func (v *apiView) Object() interface{} { @@ -112,15 +120,25 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) { func makeAPIView(api *management.ResourceServer) (*apiView, bool) { scopes, scopesTruncated := getScopes(api.GetScopes()) + + // Format subject type authorization as JSON if present. + var subjectTypeAuthJSON string + if api.SubjectTypeAuthorization != nil { + if jsonBytes, err := json.Marshal(api.SubjectTypeAuthorization); err == nil { + subjectTypeAuthJSON = string(jsonBytes) + } + } + view := &apiView{ - ID: ansi.Faint(api.GetID()), - Name: api.GetName(), - Identifier: api.GetIdentifier(), - Scopes: scopes, - TokenLifetime: api.GetTokenLifetime(), - OfflineAccess: boolean(api.GetAllowOfflineAccess()), - SigningAlgorithm: api.GetSigningAlgorithm(), - raw: api, + ID: ansi.Faint(api.GetID()), + Name: api.GetName(), + Identifier: api.GetIdentifier(), + Scopes: scopes, + TokenLifetime: api.GetTokenLifetime(), + OfflineAccess: boolean(api.GetAllowOfflineAccess()), + SigningAlgorithm: api.GetSigningAlgorithm(), + SubjectTypeAuthJSON: subjectTypeAuthJSON, + raw: api, } return view, scopesTruncated } From 8261aa4f36490eccef908778ba0f23ab36b36753 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:51:47 +0530 Subject: [PATCH 2/8] feat(tests): Add subject type authorization tests for APIs - internal/cli/apis_test.go: Implement tests for APIs with subject type authorization. - test/integration/apis-test-cases.yaml: Add integration tests for creating, updating, and showing APIs with subject type authorization. --- internal/cli/apis_test.go | 128 ++++++++++++++++++++++++++ test/integration/apis-test-cases.yaml | 32 ++++++- 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/internal/cli/apis_test.go b/internal/cli/apis_test.go index 6fe474000..74e6f4be2 100644 --- a/internal/cli/apis_test.go +++ b/internal/cli/apis_test.go @@ -47,6 +47,47 @@ func TestAPIsPickerOptions(t *testing.T) { t.Fail() }, }, + { + name: "APIs with subject type authorization", + apis: []*management.ResourceServer{ + { + ID: auth0.String("api-id-1"), + Identifier: auth0.String("https://api.example.com"), + Name: auth0.String("Example API"), + SubjectTypeAuthorization: &management.ResourceServerSubjectTypeAuthorization{ + User: &management.ResourceServerSubjectTypeAuthorizationUser{ + Policy: auth0.String("allow_all"), + }, + Client: &management.ResourceServerSubjectTypeAuthorizationClient{ + Policy: auth0.String("deny_all"), + }, + }, + }, + { + ID: auth0.String("api-id-2"), + Identifier: auth0.String("https://secure-api.example.com"), + Name: auth0.String("Secure API"), + SubjectTypeAuthorization: &management.ResourceServerSubjectTypeAuthorization{ + User: &management.ResourceServerSubjectTypeAuthorizationUser{ + Policy: auth0.String("require_client_grant"), + }, + Client: &management.ResourceServerSubjectTypeAuthorizationClient{ + Policy: auth0.String("deny_all"), + }, + }, + }, + }, + assertOutput: func(t testing.TB, options pickerOptions) { + assert.Len(t, options, 2) + assert.Equal(t, "Example API (https://api.example.com)", options[0].label) + assert.Equal(t, "api-id-1", options[0].value) + assert.Equal(t, "Secure API (https://secure-api.example.com)", options[1].label) + assert.Equal(t, "api-id-2", options[1].value) + }, + assertError: func(t testing.TB, err error) { + t.Fail() + }, + }, { name: "no apis", apis: []*management.ResourceServer{}, @@ -94,3 +135,90 @@ func TestAPIsPickerOptions(t *testing.T) { }) } } + +func TestParseSubjectTypeAuthorization(t *testing.T) { + tests := []struct { + name string + input string + expectedResult *management.ResourceServerSubjectTypeAuthorization + expectedError string + }{ + { + name: "valid complete JSON", + input: `{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}`, + expectedResult: &management.ResourceServerSubjectTypeAuthorization{ + User: &management.ResourceServerSubjectTypeAuthorizationUser{ + Policy: auth0.String("allow_all"), + }, + Client: &management.ResourceServerSubjectTypeAuthorizationClient{ + Policy: auth0.String("deny_all"), + }, + }, + }, + { + name: "valid user only JSON", + input: `{"user":{"policy":"require_client_grant"}}`, + expectedResult: &management.ResourceServerSubjectTypeAuthorization{ + User: &management.ResourceServerSubjectTypeAuthorizationUser{ + Policy: auth0.String("require_client_grant"), + }, + }, + }, + { + name: "valid client only JSON", + input: `{"client":{"policy":"deny_all"}}`, + expectedResult: &management.ResourceServerSubjectTypeAuthorization{ + Client: &management.ResourceServerSubjectTypeAuthorizationClient{ + Policy: auth0.String("deny_all"), + }, + }, + }, + { + name: "empty string input", + input: "", + expectedResult: nil, + }, + { + name: "invalid JSON syntax", + input: `{"user":{"policy":"allow_all"`, + expectedError: "invalid JSON for subject type authorization", + }, + { + name: "invalid user policy", + input: `{"user":{"policy":"invalid_policy"}}`, + expectedError: "invalid user policy: invalid_policy. Valid options: allow_all, deny_all, require_client_grant", + }, + { + name: "invalid client policy", + input: `{"client":{"policy":"allow_all"}}`, + expectedError: "invalid client policy: allow_all. Valid options: deny_all, require_client_grant", + }, + { + name: "valid JSON with unsupported fields", + input: `{"user":{"policy":"allow_all","extra":"field"},"client":{"policy":"deny_all"}}`, + expectedResult: &management.ResourceServerSubjectTypeAuthorization{ + User: &management.ResourceServerSubjectTypeAuthorizationUser{ + Policy: auth0.String("allow_all"), + }, + Client: &management.ResourceServerSubjectTypeAuthorizationClient{ + Policy: auth0.String("deny_all"), + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := parseSubjectTypeAuthorization(test.input) + + if test.expectedError != "" { + assert.Error(t, err) + assert.Contains(t, err.Error(), test.expectedError) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + assert.Equal(t, test.expectedResult, result) + } + }) + } +} diff --git a/test/integration/apis-test-cases.yaml b/test/integration/apis-test-cases.yaml index e499c636d..36b90ca15 100644 --- a/test/integration/apis-test-cases.yaml +++ b/test/integration/apis-test-cases.yaml @@ -151,7 +151,37 @@ tests: signing_alg: "HS256" exit-code: 0 - 018 - it successfully prints out a URL to open: + 019 - apis create with subject type authorization: + command: auth0 apis create --name integration-test-api-subjauth1 --identifier http://integration-test-api-subjauth1 --scopes read:todos --subject-type-authorization '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}' --json + exit-code: 0 + stdout: + json: + name: integration-test-api-subjauth1 + identifier: http://integration-test-api-subjauth1 + subject_type_authorization: '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}' + + 020 - apis create with invalid subject type authorization should fail: + command: auth0 apis create --name integration-test-api-subjauth-fail --identifier http://integration-test-api-subjauth-fail --scopes read:todos --subject-type-authorization '{"user":{"policy":"invalid_policy"}}' --json + exit-code: 1 + stderr: + contains: + - "invalid user policy: invalid_policy" + + 021 - apis update with subject type authorization: + command: auth0 apis update $(./test/integration/scripts/get-api-id.sh) --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' --json + stdout: + json: + subject_type_authorization: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + exit-code: 0 + + 022 - apis show displays subject type authorization: + command: auth0 apis show $(./test/integration/scripts/get-api-id.sh) --json + stdout: + json: + subject_type_authorization: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + exit-code: 0 + + 023 - it successfully prints out a URL to open: command: auth0 apis open $(./test/integration/scripts/get-api-id.sh) --no-input exit-code: 0 stderr: From 99d585d45abcd0c463e8b6ede53590cf04fd10a8 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:50:50 +0530 Subject: [PATCH 3/8] feat(tests): Update subject type authorization tests in apis-test-cases.yaml --- test/integration/apis-test-cases.yaml | 37 +++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/test/integration/apis-test-cases.yaml b/test/integration/apis-test-cases.yaml index 36b90ca15..cbaa2f054 100644 --- a/test/integration/apis-test-cases.yaml +++ b/test/integration/apis-test-cases.yaml @@ -3,7 +3,6 @@ config: retries: 1 tests: - 001 - list apis: command: auth0 apis list exit-code: 0 @@ -22,16 +21,16 @@ tests: - Number flag invalid, please pass a number between 1 and 1000 003 - apis create and check data: - command: auth0 apis create --name integration-test-api-def1 --identifier http://integration-test-api-def1 --scopes read:todos,write:todos --signing-alg RS256 --json - exit-code: 0 - stdout: - json: - name: integration-test-api-def1 - identifier: http://integration-test-api-def1 - scopes: "[map[value:read:todos] map[value:write:todos]]" - token_lifetime: "86400" - allow_offline_access: "false" - signing_alg: "RS256" + command: auth0 apis create --name integration-test-api-def1 --identifier http://integration-test-api-def1 --scopes read:todos,write:todos --signing-alg RS256 --json + exit-code: 0 + stdout: + json: + name: integration-test-api-def1 + identifier: http://integration-test-api-def1 + scopes: "[map[value:read:todos] map[value:write:todos]]" + token_lifetime: "86400" + allow_offline_access: "false" + signing_alg: "RS256" 004 - apis create and check output: command: auth0 apis create --name integration-test-api-def2 --identifier http://integration-test-api-def2 --scopes read:todos,write:todos --signing-alg RS256 @@ -158,30 +157,36 @@ tests: json: name: integration-test-api-subjauth1 identifier: http://integration-test-api-subjauth1 - subject_type_authorization: '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}' + subject_type_authorization: "map[client:map[policy:deny_all] user:map[policy:allow_all]]" 020 - apis create with invalid subject type authorization should fail: command: auth0 apis create --name integration-test-api-subjauth-fail --identifier http://integration-test-api-subjauth-fail --scopes read:todos --subject-type-authorization '{"user":{"policy":"invalid_policy"}}' --json exit-code: 1 stderr: contains: - - "invalid user policy: invalid_policy" + - "invalid_policy" 021 - apis update with subject type authorization: command: auth0 apis update $(./test/integration/scripts/get-api-id.sh) --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' --json stdout: json: - subject_type_authorization: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + subject_type_authorization: "map[client:map[policy:deny_all] user:map[policy:require_client_grant]]" exit-code: 0 022 - apis show displays subject type authorization: command: auth0 apis show $(./test/integration/scripts/get-api-id.sh) --json stdout: json: - subject_type_authorization: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + subject_type_authorization: "map[client:map[policy:deny_all] user:map[policy:require_client_grant]]" + exit-code: 0 + 023 - apis show displays subject type authorization with json-compact: + command: auth0 apis show $(./test/integration/scripts/get-api-id.sh) --json-compact + stdout: + json: + subject_type_authorization: "map[client:map[policy:deny_all] user:map[policy:require_client_grant]]" exit-code: 0 - 023 - it successfully prints out a URL to open: + 024 - it successfully prints out a URL to open: command: auth0 apis open $(./test/integration/scripts/get-api-id.sh) --no-input exit-code: 0 stderr: From 3a241852c9cf3c99c655f01881513d659eaac1bb Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:06:37 +0530 Subject: [PATCH 4/8] feat(tests): Add subject type authorization to API test cases --- test/integration/apis-test-cases.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/apis-test-cases.yaml b/test/integration/apis-test-cases.yaml index cbaa2f054..de286e6e5 100644 --- a/test/integration/apis-test-cases.yaml +++ b/test/integration/apis-test-cases.yaml @@ -43,6 +43,7 @@ tests: - TOKEN LIFETIME 86400 - ALLOW OFFLINE ACCESS ✗ - SIGNING ALGORITHM RS256 + - SUBJECT TYPE AUTHORIZATION # Test 'apis create' --token-lifetime flag 005 - apis create token lifetime 1000 and check data: @@ -101,6 +102,7 @@ tests: - SCOPES read:todos - TOKEN LIFETIME 86400 - ALLOW OFFLINE ACCESS ✗ + - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} exit-code: 0 012 - apis scopes list: From 9b9d71ca0226b36725e6e336eeeffbcd22a56fa6 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:23:09 +0530 Subject: [PATCH 5/8] feat(tests): Update subject type authorization in API test cases --- test/integration/apis-test-cases.yaml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/integration/apis-test-cases.yaml b/test/integration/apis-test-cases.yaml index de286e6e5..7b13169eb 100644 --- a/test/integration/apis-test-cases.yaml +++ b/test/integration/apis-test-cases.yaml @@ -43,7 +43,7 @@ tests: - TOKEN LIFETIME 86400 - ALLOW OFFLINE ACCESS ✗ - SIGNING ALGORITHM RS256 - - SUBJECT TYPE AUTHORIZATION + - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} # Test 'apis create' --token-lifetime flag 005 - apis create token lifetime 1000 and check data: @@ -58,7 +58,13 @@ tests: exit-code: 0 stdout: contains: + - NAME integration-test-api-toklif2 + - IDENTIFIER http://integration-test-api-toklif2 + - SCOPES read:todos - TOKEN LIFETIME 1000 + - ALLOW OFFLINE ACCESS ✗ + - SIGNING ALGORITHM RS256 + - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} # Test 'apis create' --offline-access flag 007 - apis create offline access true and check data: @@ -73,7 +79,13 @@ tests: exit-code: 0 stdout: contains: - - ALLOW OFFLINE ACCESS ✓ + - NAME integration-test-api-offacc2 + - IDENTIFIER http://integration-test-api-offacc2 + - SCOPES read:todos + - TOKEN LIFETIME 86400 + - ALLOW OFFLINE ACCESS ✓ + - SIGNING ALGORITHM RS256 + - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} 009 - apis create offline access false and check data: command: auth0 apis create --name integration-test-api-offacc3 --identifier http://integration-test-api-offacc3 --scopes read:todos --offline-access=false --json @@ -97,11 +109,12 @@ tests: command: auth0 apis show $(./test/integration/scripts/get-api-id.sh) # depends on "apis create test app" test stdout: contains: - - NAME integration-test-api-newapi - - IDENTIFIER http://integration-test-api-newapi - - SCOPES read:todos - - TOKEN LIFETIME 86400 - - ALLOW OFFLINE ACCESS ✗ + - NAME integration-test-api-newapi + - IDENTIFIER http://integration-test-api-newapi + - SCOPES read:todos + - TOKEN LIFETIME 86400 + - ALLOW OFFLINE ACCESS ✗ + - SIGNING ALGORITHM RS256 - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} exit-code: 0 From cb7c10625886d6c2cc823881164370cc27c51600 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Thu, 21 Aug 2025 13:02:27 +0530 Subject: [PATCH 6/8] feat(tests): Update subject type authorization in API test cases --- test/integration/apis-test-cases.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/integration/apis-test-cases.yaml b/test/integration/apis-test-cases.yaml index 7b13169eb..58ea0ce72 100644 --- a/test/integration/apis-test-cases.yaml +++ b/test/integration/apis-test-cases.yaml @@ -37,12 +37,12 @@ tests: exit-code: 0 stdout: contains: - - NAME integration-test-api-def2 - - IDENTIFIER http://integration-test-api-def2 - - SCOPES read:todos write:todos - - TOKEN LIFETIME 86400 - - ALLOW OFFLINE ACCESS ✗ - - SIGNING ALGORITHM RS256 + - NAME integration-test-api-def2 + - IDENTIFIER http://integration-test-api-def2 + - SCOPES read:todos write:todos + - TOKEN LIFETIME 86400 + - ALLOW OFFLINE ACCESS ✗ + - SIGNING ALGORITHM RS256 - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} # Test 'apis create' --token-lifetime flag @@ -58,12 +58,12 @@ tests: exit-code: 0 stdout: contains: - - NAME integration-test-api-toklif2 - - IDENTIFIER http://integration-test-api-toklif2 - - SCOPES read:todos - - TOKEN LIFETIME 1000 - - ALLOW OFFLINE ACCESS ✗ - - SIGNING ALGORITHM RS256 + - NAME integration-test-api-toklif2 + - IDENTIFIER http://integration-test-api-toklif2 + - SCOPES read:todos + - TOKEN LIFETIME 1000 + - ALLOW OFFLINE ACCESS ✗ + - SIGNING ALGORITHM RS256 - SUBJECT TYPE AUTHORIZATION {"user":{"policy":"allow_all"},"client":{"policy":"require_client_grant"}} # Test 'apis create' --offline-access flag From 7a5a1f425642feffd973a60463ad4c1030583116 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Sat, 30 Aug 2025 21:13:30 +0530 Subject: [PATCH 7/8] feat(go.mod): update go-auth0 to v1.27.0 feat(go.sum): update go-auth0 checksum for v1.27.0 refactor(internal/cli/apis.go): simplify subject type authorization handling refactor(internal/cli/apis.go): remove unused subject type policy constants refactor(internal/cli/apis_test.go): remove parseSubjectTypeAuthorization test refactor(internal/display/apis.go): change subject type authorization JSON formatting --- go.mod | 4 +- go.sum | 8 ++-- internal/cli/apis.go | 79 ++++++----------------------------- internal/cli/apis_test.go | 87 --------------------------------------- internal/display/apis.go | 6 +-- 5 files changed, 20 insertions(+), 164 deletions(-) diff --git a/go.mod b/go.mod index 06ae88837..04e2bf84f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 github.com/atotto/clipboard v0.1.4 - github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0 + github.com/auth0/go-auth0 v1.27.0 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v0.10.0 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e @@ -32,7 +32,7 @@ require ( github.com/schollz/progressbar/v3 v3.17.1 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/tidwall/pretty v1.2.1 github.com/zalando/go-keyring v0.2.6 golang.org/x/net v0.42.0 diff --git a/go.sum b/go.sum index cc3aaf45a..9d0a0a5ee 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0 h1:DuuXNV1roDiC7Kh6TjnQE3KIiP2hUor31DtmPgaihwI= -github.com/auth0/go-auth0 v1.26.1-0.20250818123516-b38cada021f0/go.mod h1:g9S/4ImupKFx1gSLqeQO0v1yV91Oo5J5bYobLCAL+J4= +github.com/auth0/go-auth0 v1.27.0 h1:f2gC//Ig0v2CH7j3T5zEz/L8xWTH+Z7jLb4ORrfvgNA= +github.com/auth0/go-auth0 v1.27.0/go.mod h1:rLrZQWStpXQ23Uo0xRlTkXJXIR0oNVudaJWlvUnUqeI= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -229,8 +229,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= diff --git a/internal/cli/apis.go b/internal/cli/apis.go index ce17f37b8..cbf10445c 100644 --- a/internal/cli/apis.go +++ b/internal/cli/apis.go @@ -7,7 +7,6 @@ import ( "fmt" "net/url" "strconv" - "strings" "github.com/auth0/go-auth0" "github.com/auth0/go-auth0/management" @@ -19,13 +18,6 @@ import ( const apiDefaultTokenLifetime = 86400 -// Subject Type Authorization Policy Constants. -const ( - subjectTypePolicyAllowAll = "allow_all" - subjectTypePolicyDenyAll = "deny_all" - subjectTypePolicyRequireClientGrant = "require_client_grant" -) - var ( apiID = Argument{ Name: "Id", @@ -303,12 +295,12 @@ func createAPICmd(cli *cli) *cobra.Command { api.TokenLifetime = auth0.Int(inputs.TokenLifetime) } - if len(inputs.SubjectTypeAuthorization) > 0 { - subjectTypeAuth, err := parseSubjectTypeAuthorization(inputs.SubjectTypeAuthorization) - if err != nil { - return err + if inputs.SubjectTypeAuthorization != "{}" { + var subjectTypeAuth management.ResourceServerSubjectTypeAuthorization + if err := json.Unmarshal([]byte(inputs.SubjectTypeAuthorization), &subjectTypeAuth); err != nil { + return fmt.Errorf("invalid JSON for subject-type-authorization: %w", err) } - api.SubjectTypeAuthorization = subjectTypeAuth + api.SubjectTypeAuthorization = &subjectTypeAuth } if err := ansi.Waiting(func() error { @@ -336,7 +328,7 @@ func createAPICmd(cli *cli) *cobra.Command { apiOfflineAccess.RegisterBool(cmd, &inputs.AllowOfflineAccess, false) apiTokenLifetime.RegisterInt(cmd, &inputs.TokenLifetime, 0) apiSigningAlgorithm.RegisterString(cmd, &inputs.SigningAlgorithm, "RS256") - apiSubjectTypeAuthorization.RegisterString(cmd, &inputs.SubjectTypeAuthorization, "") + apiSubjectTypeAuthorization.RegisterString(cmd, &inputs.SubjectTypeAuthorization, "{}") return cmd } @@ -448,12 +440,12 @@ func updateAPICmd(cli *cli) *cobra.Command { } api.SubjectTypeAuthorization = current.SubjectTypeAuthorization - if inputs.SubjectTypeAuthorization != "" { - subjectTypeAuth, err := parseSubjectTypeAuthorization(inputs.SubjectTypeAuthorization) - if err != nil { - return err + if inputs.SubjectTypeAuthorization != "{}" { + var subjectTypeAuth management.ResourceServerSubjectTypeAuthorization + if err := json.Unmarshal([]byte(inputs.SubjectTypeAuthorization), &subjectTypeAuth); err != nil { + return fmt.Errorf("invalid JSON for subject-type-authorization: %w", err) } - api.SubjectTypeAuthorization = subjectTypeAuth + api.SubjectTypeAuthorization = &subjectTypeAuth } if err := ansi.Waiting(func() error { @@ -475,7 +467,7 @@ func updateAPICmd(cli *cli) *cobra.Command { apiOfflineAccess.RegisterBoolU(cmd, &inputs.AllowOfflineAccess, false) apiTokenLifetime.RegisterIntU(cmd, &inputs.TokenLifetime, 0) apiSigningAlgorithm.RegisterStringU(cmd, &inputs.SigningAlgorithm, "RS256") - apiSubjectTypeAuthorization.RegisterStringU(cmd, &inputs.SubjectTypeAuthorization, "") + apiSubjectTypeAuthorization.RegisterStringU(cmd, &inputs.SubjectTypeAuthorization, "{}") return cmd } @@ -678,50 +670,3 @@ func (c *cli) filteredAPIPickerOptions(ctx context.Context, include func(r *mana return opts, nil } - -func parseSubjectTypeAuthorization(jsonStr string) (*management.ResourceServerSubjectTypeAuthorization, error) { - if jsonStr == "" { - return nil, nil - } - - var result management.ResourceServerSubjectTypeAuthorization - if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { - return nil, fmt.Errorf("invalid JSON for subject type authorization: %w", err) - } - - // Define valid policies for each flow type. - validUserPolicies := []string{subjectTypePolicyAllowAll, subjectTypePolicyDenyAll, subjectTypePolicyRequireClientGrant} - validClientPolicies := []string{subjectTypePolicyDenyAll, subjectTypePolicyRequireClientGrant} - - // Validate user policy. - if result.User != nil && result.User.Policy != nil { - userPolicy := *result.User.Policy - isValid := false - for _, valid := range validUserPolicies { - if userPolicy == valid { - isValid = true - break - } - } - if !isValid { - return nil, fmt.Errorf("invalid user policy: %s. Valid options: %s", userPolicy, strings.Join(validUserPolicies, ", ")) - } - } - - // Validate client policy. - if result.Client != nil && result.Client.Policy != nil { - clientPolicy := *result.Client.Policy - isValid := false - for _, valid := range validClientPolicies { - if clientPolicy == valid { - isValid = true - break - } - } - if !isValid { - return nil, fmt.Errorf("invalid client policy: %s. Valid options: %s", clientPolicy, strings.Join(validClientPolicies, ", ")) - } - } - - return &result, nil -} diff --git a/internal/cli/apis_test.go b/internal/cli/apis_test.go index 74e6f4be2..f13b64ebc 100644 --- a/internal/cli/apis_test.go +++ b/internal/cli/apis_test.go @@ -135,90 +135,3 @@ func TestAPIsPickerOptions(t *testing.T) { }) } } - -func TestParseSubjectTypeAuthorization(t *testing.T) { - tests := []struct { - name string - input string - expectedResult *management.ResourceServerSubjectTypeAuthorization - expectedError string - }{ - { - name: "valid complete JSON", - input: `{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}`, - expectedResult: &management.ResourceServerSubjectTypeAuthorization{ - User: &management.ResourceServerSubjectTypeAuthorizationUser{ - Policy: auth0.String("allow_all"), - }, - Client: &management.ResourceServerSubjectTypeAuthorizationClient{ - Policy: auth0.String("deny_all"), - }, - }, - }, - { - name: "valid user only JSON", - input: `{"user":{"policy":"require_client_grant"}}`, - expectedResult: &management.ResourceServerSubjectTypeAuthorization{ - User: &management.ResourceServerSubjectTypeAuthorizationUser{ - Policy: auth0.String("require_client_grant"), - }, - }, - }, - { - name: "valid client only JSON", - input: `{"client":{"policy":"deny_all"}}`, - expectedResult: &management.ResourceServerSubjectTypeAuthorization{ - Client: &management.ResourceServerSubjectTypeAuthorizationClient{ - Policy: auth0.String("deny_all"), - }, - }, - }, - { - name: "empty string input", - input: "", - expectedResult: nil, - }, - { - name: "invalid JSON syntax", - input: `{"user":{"policy":"allow_all"`, - expectedError: "invalid JSON for subject type authorization", - }, - { - name: "invalid user policy", - input: `{"user":{"policy":"invalid_policy"}}`, - expectedError: "invalid user policy: invalid_policy. Valid options: allow_all, deny_all, require_client_grant", - }, - { - name: "invalid client policy", - input: `{"client":{"policy":"allow_all"}}`, - expectedError: "invalid client policy: allow_all. Valid options: deny_all, require_client_grant", - }, - { - name: "valid JSON with unsupported fields", - input: `{"user":{"policy":"allow_all","extra":"field"},"client":{"policy":"deny_all"}}`, - expectedResult: &management.ResourceServerSubjectTypeAuthorization{ - User: &management.ResourceServerSubjectTypeAuthorizationUser{ - Policy: auth0.String("allow_all"), - }, - Client: &management.ResourceServerSubjectTypeAuthorizationClient{ - Policy: auth0.String("deny_all"), - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - result, err := parseSubjectTypeAuthorization(test.input) - - if test.expectedError != "" { - assert.Error(t, err) - assert.Contains(t, err.Error(), test.expectedError) - assert.Nil(t, result) - } else { - assert.NoError(t, err) - assert.Equal(t, test.expectedResult, result) - } - }) - } -} diff --git a/internal/display/apis.go b/internal/display/apis.go index ef2f501de..f78cacf3f 100644 --- a/internal/display/apis.go +++ b/internal/display/apis.go @@ -1,7 +1,6 @@ package display import ( - "encoding/json" "fmt" "strconv" "strings" @@ -121,11 +120,10 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) { func makeAPIView(api *management.ResourceServer) (*apiView, bool) { scopes, scopesTruncated := getScopes(api.GetScopes()) - // Format subject type authorization as JSON if present. var subjectTypeAuthJSON string if api.SubjectTypeAuthorization != nil { - if jsonBytes, err := json.Marshal(api.SubjectTypeAuthorization); err == nil { - subjectTypeAuthJSON = string(jsonBytes) + if subjectTypeAuthString, err := toJSONString(api.SubjectTypeAuthorization); err == nil { + subjectTypeAuthJSON = subjectTypeAuthString } } From 8a6c070c4b4830b21bff3457d22d96caa12c61a9 Mon Sep 17 00:00:00 2001 From: kushalshit27 <43465488+kushalshit27@users.noreply.github.com> Date: Sat, 30 Aug 2025 21:15:30 +0530 Subject: [PATCH 8/8] feat(docs): update subject-type-authorization flag description --- docs/auth0_apis_create.md | 2 +- docs/auth0_apis_update.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth0_apis_create.md b/docs/auth0_apis_create.md index 251bc9537..7265e12b2 100644 --- a/docs/auth0_apis_create.md +++ b/docs/auth0_apis_create.md @@ -42,7 +42,7 @@ auth0 apis create [flags] -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). -s, --scopes strings Comma-separated list of scopes (permissions). --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") - --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' (default "{}") -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). ``` diff --git a/docs/auth0_apis_update.md b/docs/auth0_apis_update.md index 538da6e00..fee11abac 100644 --- a/docs/auth0_apis_update.md +++ b/docs/auth0_apis_update.md @@ -40,7 +40,7 @@ auth0 apis update [flags] -o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false). -s, --scopes strings Comma-separated list of scopes (permissions). --signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256") - --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' + --subject-type-authorization string JSON object defining access policies for user and client flows. Example: '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}' (default "{}") -l, --token-lifetime int The amount of time in seconds that the token will be valid after being issued. Default value is 86400 seconds (1 day). ```