Skip to content

Commit 3a9c43e

Browse files
authored
feat: Support application access permissions (#1315)
1 parent 387ba35 commit 3a9c43e

8 files changed

Lines changed: 232 additions & 76 deletions

File tree

docs/auth0_apis_create.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,22 @@ auth0 apis create [flags]
2828
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
2929
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
3030
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
31+
auth0 apis create --name myapi --identifier http://my-api --subject-type-authorization '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}'
3132
```
3233

3334

3435
## Flags
3536

3637
```
37-
-i, --identifier string Identifier of the API. Cannot be changed once set.
38-
--json Output in json format.
39-
--json-compact Output in compact json format.
40-
-n, --name string Name of the API.
41-
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
42-
-s, --scopes strings Comma-separated list of scopes (permissions).
43-
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
44-
-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).
38+
-i, --identifier string Identifier of the API. Cannot be changed once set.
39+
--json Output in json format.
40+
--json-compact Output in compact json format.
41+
-n, --name string Name of the API.
42+
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
43+
-s, --scopes strings Comma-separated list of scopes (permissions).
44+
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
45+
--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 "{}")
46+
-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).
4547
```
4648

4749

docs/auth0_apis_update.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@ auth0 apis update [flags]
2727
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
2828
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
2929
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
30+
auth0 apis update <api-id|api-audience> --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}'
3031
```
3132

3233

3334
## Flags
3435

3536
```
36-
--json Output in json format.
37-
--json-compact Output in compact json format.
38-
-n, --name string Name of the API.
39-
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
40-
-s, --scopes strings Comma-separated list of scopes (permissions).
41-
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
42-
-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).
37+
--json Output in json format.
38+
--json-compact Output in compact json format.
39+
-n, --name string Name of the API.
40+
-o, --offline-access Whether Refresh Tokens can be issued for this API (true) or not (false).
41+
-s, --scopes strings Comma-separated list of scopes (permissions).
42+
--signing-alg string Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon. (default "RS256")
43+
--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 "{}")
44+
-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).
4345
```
4446

4547

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/AlecAivazis/survey/v2 v2.3.7
77
github.com/PuerkitoBio/rehttp v1.4.0
88
github.com/atotto/clipboard v0.1.4
9-
github.com/auth0/go-auth0 v1.25.0
9+
github.com/auth0/go-auth0 v1.27.0
1010
github.com/briandowns/spinner v1.23.2
1111
github.com/charmbracelet/glamour v0.10.0
1212
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
@@ -32,7 +32,7 @@ require (
3232
github.com/schollz/progressbar/v3 v3.17.1
3333
github.com/spf13/cobra v1.9.1
3434
github.com/spf13/pflag v1.0.6
35-
github.com/stretchr/testify v1.10.0
35+
github.com/stretchr/testify v1.11.1
3636
github.com/tidwall/pretty v1.2.1
3737
github.com/zalando/go-keyring v0.2.6
3838
golang.org/x/net v0.42.0

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
2222
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
2323
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2424
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
25-
github.com/auth0/go-auth0 v1.25.0 h1:fNlbDL8CPA+w3mfuuGD12cHjtEK/EDLJAc20xrL1+Eg=
26-
github.com/auth0/go-auth0 v1.25.0/go.mod h1:g9S/4ImupKFx1gSLqeQO0v1yV91Oo5J5bYobLCAL+J4=
25+
github.com/auth0/go-auth0 v1.27.0 h1:f2gC//Ig0v2CH7j3T5zEz/L8xWTH+Z7jLb4ORrfvgNA=
26+
github.com/auth0/go-auth0 v1.27.0/go.mod h1:rLrZQWStpXQ23Uo0xRlTkXJXIR0oNVudaJWlvUnUqeI=
2727
github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48=
2828
github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA=
2929
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/
229229
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
230230
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
231231
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
232-
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
233-
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
232+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
233+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
234234
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
235235
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
236236
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=

internal/cli/apis.go

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cli
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"fmt"
78
"net/url"
@@ -68,6 +69,11 @@ var (
6869
ShortForm: "n",
6970
Help: "Number of APIs to retrieve. Minimum 1, maximum 1000.",
7071
}
72+
apiSubjectTypeAuthorization = Flag{
73+
Name: "Subject Type Authorization",
74+
LongForm: "subject-type-authorization",
75+
Help: "JSON object defining access policies for user and client flows. Example: '{\"user\":{\"policy\":\"require_client_grant\"},\"client\":{\"policy\":\"deny_all\"}}'",
76+
}
7177
)
7278

7379
func apisCmd(cli *cli) *cobra.Command {
@@ -214,12 +220,13 @@ func showAPICmd(cli *cli) *cobra.Command {
214220

215221
func createAPICmd(cli *cli) *cobra.Command {
216222
var inputs struct {
217-
Name string
218-
Identifier string
219-
Scopes []string
220-
TokenLifetime int
221-
AllowOfflineAccess bool
222-
SigningAlgorithm string
223+
Name string
224+
Identifier string
225+
Scopes []string
226+
TokenLifetime int
227+
AllowOfflineAccess bool
228+
SigningAlgorithm string
229+
SubjectTypeAuthorization string
223230
}
224231

225232
cmd := &cobra.Command{
@@ -238,7 +245,8 @@ func createAPICmd(cli *cli) *cobra.Command {
238245
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
239246
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
240247
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
241-
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact`,
248+
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
249+
auth0 apis create --name myapi --identifier http://my-api --subject-type-authorization '{"user":{"policy":"allow_all"},"client":{"policy":"deny_all"}}'`,
242250
RunE: func(cmd *cobra.Command, args []string) error {
243251
if err := apiName.Ask(cmd, &inputs.Name, nil); err != nil {
244252
return err
@@ -265,6 +273,10 @@ func createAPICmd(cli *cli) *cobra.Command {
265273
return err
266274
}
267275

276+
if err := apiSubjectTypeAuthorization.Ask(cmd, &inputs.SubjectTypeAuthorization, nil); err != nil {
277+
return err
278+
}
279+
268280
api := &management.ResourceServer{
269281
Name: &inputs.Name,
270282
Identifier: &inputs.Identifier,
@@ -283,6 +295,14 @@ func createAPICmd(cli *cli) *cobra.Command {
283295
api.TokenLifetime = auth0.Int(inputs.TokenLifetime)
284296
}
285297

298+
if inputs.SubjectTypeAuthorization != "{}" {
299+
var subjectTypeAuth management.ResourceServerSubjectTypeAuthorization
300+
if err := json.Unmarshal([]byte(inputs.SubjectTypeAuthorization), &subjectTypeAuth); err != nil {
301+
return fmt.Errorf("invalid JSON for subject-type-authorization: %w", err)
302+
}
303+
api.SubjectTypeAuthorization = &subjectTypeAuth
304+
}
305+
286306
if err := ansi.Waiting(func() error {
287307
return cli.api.ResourceServer.Create(cmd.Context(), api)
288308
}); err != nil {
@@ -308,18 +328,20 @@ func createAPICmd(cli *cli) *cobra.Command {
308328
apiOfflineAccess.RegisterBool(cmd, &inputs.AllowOfflineAccess, false)
309329
apiTokenLifetime.RegisterInt(cmd, &inputs.TokenLifetime, 0)
310330
apiSigningAlgorithm.RegisterString(cmd, &inputs.SigningAlgorithm, "RS256")
331+
apiSubjectTypeAuthorization.RegisterString(cmd, &inputs.SubjectTypeAuthorization, "{}")
311332

312333
return cmd
313334
}
314335

315336
func updateAPICmd(cli *cli) *cobra.Command {
316337
var inputs struct {
317-
ID string
318-
Name string
319-
Scopes []string
320-
TokenLifetime int
321-
AllowOfflineAccess bool
322-
SigningAlgorithm string
338+
ID string
339+
Name string
340+
Scopes []string
341+
TokenLifetime int
342+
AllowOfflineAccess bool
343+
SigningAlgorithm string
344+
SubjectTypeAuthorization string
323345
}
324346

325347
cmd := &cobra.Command{
@@ -337,7 +359,8 @@ func updateAPICmd(cli *cli) *cobra.Command {
337359
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false
338360
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read" --signing-alg "RS256"
339361
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json
340-
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact`,
362+
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --signing-alg "RS256" --json-compact
363+
auth0 apis update <api-id|api-audience> --subject-type-authorization '{"user":{"policy":"require_client_grant"},"client":{"policy":"deny_all"}}'`,
341364
RunE: func(cmd *cobra.Command, args []string) error {
342365
if len(args) == 0 {
343366
if err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions); err != nil {
@@ -380,6 +403,18 @@ func updateAPICmd(cli *cli) *cobra.Command {
380403
return err
381404
}
382405

406+
// Current subject type authorization value for display.
407+
var currentSubjectTypeJSON string
408+
if current.SubjectTypeAuthorization != nil {
409+
if jsonBytes, err := json.Marshal(current.SubjectTypeAuthorization); err == nil {
410+
currentSubjectTypeJSON = string(jsonBytes)
411+
}
412+
}
413+
414+
if err := apiSubjectTypeAuthorization.AskU(cmd, &inputs.SubjectTypeAuthorization, &currentSubjectTypeJSON); err != nil {
415+
return err
416+
}
417+
383418
api := &management.ResourceServer{
384419
AllowOfflineAccess: &inputs.AllowOfflineAccess,
385420
}
@@ -404,6 +439,15 @@ func updateAPICmd(cli *cli) *cobra.Command {
404439
api.SigningAlgorithm = &inputs.SigningAlgorithm
405440
}
406441

442+
api.SubjectTypeAuthorization = current.SubjectTypeAuthorization
443+
if inputs.SubjectTypeAuthorization != "{}" {
444+
var subjectTypeAuth management.ResourceServerSubjectTypeAuthorization
445+
if err := json.Unmarshal([]byte(inputs.SubjectTypeAuthorization), &subjectTypeAuth); err != nil {
446+
return fmt.Errorf("invalid JSON for subject-type-authorization: %w", err)
447+
}
448+
api.SubjectTypeAuthorization = &subjectTypeAuth
449+
}
450+
407451
if err := ansi.Waiting(func() error {
408452
return cli.api.ResourceServer.Update(cmd.Context(), current.GetID(), api)
409453
}); err != nil {
@@ -423,6 +467,7 @@ func updateAPICmd(cli *cli) *cobra.Command {
423467
apiOfflineAccess.RegisterBoolU(cmd, &inputs.AllowOfflineAccess, false)
424468
apiTokenLifetime.RegisterIntU(cmd, &inputs.TokenLifetime, 0)
425469
apiSigningAlgorithm.RegisterStringU(cmd, &inputs.SigningAlgorithm, "RS256")
470+
apiSubjectTypeAuthorization.RegisterStringU(cmd, &inputs.SubjectTypeAuthorization, "{}")
426471

427472
return cmd
428473
}

internal/cli/apis_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,47 @@ func TestAPIsPickerOptions(t *testing.T) {
4747
t.Fail()
4848
},
4949
},
50+
{
51+
name: "APIs with subject type authorization",
52+
apis: []*management.ResourceServer{
53+
{
54+
ID: auth0.String("api-id-1"),
55+
Identifier: auth0.String("https://api.example.com"),
56+
Name: auth0.String("Example API"),
57+
SubjectTypeAuthorization: &management.ResourceServerSubjectTypeAuthorization{
58+
User: &management.ResourceServerSubjectTypeAuthorizationUser{
59+
Policy: auth0.String("allow_all"),
60+
},
61+
Client: &management.ResourceServerSubjectTypeAuthorizationClient{
62+
Policy: auth0.String("deny_all"),
63+
},
64+
},
65+
},
66+
{
67+
ID: auth0.String("api-id-2"),
68+
Identifier: auth0.String("https://secure-api.example.com"),
69+
Name: auth0.String("Secure API"),
70+
SubjectTypeAuthorization: &management.ResourceServerSubjectTypeAuthorization{
71+
User: &management.ResourceServerSubjectTypeAuthorizationUser{
72+
Policy: auth0.String("require_client_grant"),
73+
},
74+
Client: &management.ResourceServerSubjectTypeAuthorizationClient{
75+
Policy: auth0.String("deny_all"),
76+
},
77+
},
78+
},
79+
},
80+
assertOutput: func(t testing.TB, options pickerOptions) {
81+
assert.Len(t, options, 2)
82+
assert.Equal(t, "Example API (https://api.example.com)", options[0].label)
83+
assert.Equal(t, "api-id-1", options[0].value)
84+
assert.Equal(t, "Secure API (https://secure-api.example.com)", options[1].label)
85+
assert.Equal(t, "api-id-2", options[1].value)
86+
},
87+
assertError: func(t testing.TB, err error) {
88+
t.Fail()
89+
},
90+
},
5091
{
5192
name: "no apis",
5293
apis: []*management.ResourceServer{},

internal/display/apis.go

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ import (
1313
)
1414

1515
type apiView struct {
16-
ID string
17-
Name string
18-
Identifier string
19-
Scopes string
20-
TokenLifetime int
21-
OfflineAccess string
22-
SigningAlgorithm string
16+
ID string
17+
Name string
18+
Identifier string
19+
Scopes string
20+
TokenLifetime int
21+
OfflineAccess string
22+
SigningAlgorithm string
23+
SubjectTypeAuthJSON string
2324

2425
raw interface{}
2526
}
@@ -33,7 +34,7 @@ func (v *apiView) AsTableRow() []string {
3334
}
3435

3536
func (v *apiView) KeyValues() [][]string {
36-
return [][]string{
37+
kvs := [][]string{
3738
{"ID", ansi.Faint(v.ID)},
3839
{"NAME", v.Name},
3940
{"IDENTIFIER", v.Identifier},
@@ -42,6 +43,12 @@ func (v *apiView) KeyValues() [][]string {
4243
{"ALLOW OFFLINE ACCESS", v.OfflineAccess},
4344
{"SIGNING ALGORITHM", v.SigningAlgorithm},
4445
}
46+
47+
if len(v.SubjectTypeAuthJSON) > 0 {
48+
kvs = append(kvs, []string{"SUBJECT TYPE AUTHORIZATION", v.SubjectTypeAuthJSON})
49+
}
50+
51+
return kvs
4552
}
4653

4754
func (v *apiView) Object() interface{} {
@@ -112,15 +119,24 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) {
112119

113120
func makeAPIView(api *management.ResourceServer) (*apiView, bool) {
114121
scopes, scopesTruncated := getScopes(api.GetScopes())
122+
123+
var subjectTypeAuthJSON string
124+
if api.SubjectTypeAuthorization != nil {
125+
if subjectTypeAuthString, err := toJSONString(api.SubjectTypeAuthorization); err == nil {
126+
subjectTypeAuthJSON = subjectTypeAuthString
127+
}
128+
}
129+
115130
view := &apiView{
116-
ID: ansi.Faint(api.GetID()),
117-
Name: api.GetName(),
118-
Identifier: api.GetIdentifier(),
119-
Scopes: scopes,
120-
TokenLifetime: api.GetTokenLifetime(),
121-
OfflineAccess: boolean(api.GetAllowOfflineAccess()),
122-
SigningAlgorithm: api.GetSigningAlgorithm(),
123-
raw: api,
131+
ID: ansi.Faint(api.GetID()),
132+
Name: api.GetName(),
133+
Identifier: api.GetIdentifier(),
134+
Scopes: scopes,
135+
TokenLifetime: api.GetTokenLifetime(),
136+
OfflineAccess: boolean(api.GetAllowOfflineAccess()),
137+
SigningAlgorithm: api.GetSigningAlgorithm(),
138+
SubjectTypeAuthJSON: subjectTypeAuthJSON,
139+
raw: api,
124140
}
125141
return view, scopesTruncated
126142
}

0 commit comments

Comments
 (0)