Skip to content
Merged
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
18 changes: 10 additions & 8 deletions docs/auth0_apis_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}' (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).
```


Expand Down
16 changes: 9 additions & 7 deletions docs/auth0_apis_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@ auth0 apis update [flags]
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
auth0 apis update <api-id|api-audience> --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"}}' (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).
```


Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.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
Expand All @@ -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
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.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=
Expand Down Expand Up @@ -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=
Expand Down
73 changes: 59 additions & 14 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
Expand Down Expand Up @@ -68,6 +69,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 {
Expand Down Expand Up @@ -214,12 +220,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{
Expand All @@ -238,7 +245,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
Expand All @@ -265,6 +273,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,
Expand All @@ -283,6 +295,14 @@ func createAPICmd(cli *cli) *cobra.Command {
api.TokenLifetime = auth0.Int(inputs.TokenLifetime)
}

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
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Create(cmd.Context(), api)
}); err != nil {
Expand All @@ -308,18 +328,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{
Expand All @@ -337,7 +359,8 @@ func updateAPICmd(cli *cli) *cobra.Command {
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact`,
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
auth0 apis update <api-id|api-audience> --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 {
Expand Down Expand Up @@ -380,6 +403,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, &currentSubjectTypeJSON); err != nil {
return err
}

api := &management.ResourceServer{
AllowOfflineAccess: &inputs.AllowOfflineAccess,
}
Expand All @@ -404,6 +439,15 @@ func updateAPICmd(cli *cli) *cobra.Command {
api.SigningAlgorithm = &inputs.SigningAlgorithm
}

api.SubjectTypeAuthorization = current.SubjectTypeAuthorization
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
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Update(cmd.Context(), current.GetID(), api)
}); err != nil {
Expand All @@ -423,6 +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, "{}")

return cmd
}
Expand Down
41 changes: 41 additions & 0 deletions internal/cli/apis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{},
Expand Down
48 changes: 32 additions & 16 deletions internal/display/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,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{}
}
Expand All @@ -33,7 +34,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},
Expand All @@ -42,6 +43,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{} {
Expand Down Expand Up @@ -112,15 +119,24 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) {

func makeAPIView(api *management.ResourceServer) (*apiView, bool) {
scopes, scopesTruncated := getScopes(api.GetScopes())

var subjectTypeAuthJSON string
if api.SubjectTypeAuthorization != nil {
if subjectTypeAuthString, err := toJSONString(api.SubjectTypeAuthorization); err == nil {
subjectTypeAuthJSON = subjectTypeAuthString
}
}

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
}
Expand Down
Loading
Loading