Skip to content

Commit

Permalink
DXCDT-595: Add ability to update signing alg for apis (#926)
Browse files Browse the repository at this point in the history
* Add ability to update signing alg for apis

* Removing short alias

---------

Co-authored-by: Will Vedder <[email protected]>
  • Loading branch information
sergiught and willvedd authored Nov 30, 2023
1 parent a855697 commit fd9092c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 51 deletions.
4 changes: 3 additions & 1 deletion docs/auth0_apis_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ auth0 apis create [flags]
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=true
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --json
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
```


Expand All @@ -37,6 +38,7 @@ auth0 apis create [flags]
-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).
```

Expand Down
5 changes: 3 additions & 2 deletions docs/auth0_apis_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ auth0 apis update [flags]
auth0 apis update <api-id|api-audience> --name myapi
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100
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"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --json
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
```


Expand All @@ -36,6 +36,7 @@ auth0 apis update [flags]
-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).
```

Expand Down
86 changes: 54 additions & 32 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/auth0/auth0-cli/internal/prompt"
)

const apiDefaultTokenLifetime = 86400

var (
apiID = Argument{
Name: "Id",
Expand Down Expand Up @@ -55,6 +57,11 @@ var (
Help: "Whether Refresh Tokens can be issued for this API (true) or not (false).",
AlwaysPrompt: true,
}
apiSigningAlgorithm = Flag{
Name: "Signing Algorithm",
LongForm: "signing-alg",
Help: "Algorithm used to sign JWTs. Can be HS256 or RS256. PS256 available via addon.",
}
apiNumber = Flag{
Name: "Number",
LongForm: "number",
Expand Down Expand Up @@ -204,6 +211,7 @@ func createAPICmd(cli *cli) *cobra.Command {
Scopes []string
TokenLifetime int
AllowOfflineAccess bool
SigningAlgorithm string
}

cmd := &cobra.Command{
Expand All @@ -220,7 +228,8 @@ func createAPICmd(cli *cli) *cobra.Command {
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=true
auth0 apis create --name myapi --identifier http://my-api --token-lifetime 6100 --offline-access=false --scopes "letter:write,letter:read"
auth0 apis create -n myapi -i http://my-api -t 6100 -o false -s "letter:write,letter:read" --json`,
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`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := apiName.Ask(cmd, &inputs.Name, nil); err != nil {
return err
Expand All @@ -234,7 +243,7 @@ func createAPICmd(cli *cli) *cobra.Command {
return err
}

defaultTokenLifetime := strconv.Itoa(apiDefaultTokenLifetime())
defaultTokenLifetime := strconv.Itoa(apiDefaultTokenLifetime)
if err := apiTokenLifetime.Ask(cmd, &inputs.TokenLifetime, &defaultTokenLifetime); err != nil {
return err
}
Expand All @@ -243,31 +252,41 @@ func createAPICmd(cli *cli) *cobra.Command {
return err
}

if err := apiSigningAlgorithm.Ask(cmd, &inputs.SigningAlgorithm, auth0.String("RS256")); err != nil {
return err
}

api := &management.ResourceServer{
Name: &inputs.Name,
Identifier: &inputs.Identifier,
AllowOfflineAccess: &inputs.AllowOfflineAccess,
TokenLifetime: &inputs.TokenLifetime,
SigningAlgorithm: &inputs.SigningAlgorithm,
}

if len(inputs.Scopes) > 0 {
api.Scopes = apiScopesFor(inputs.Scopes)
}

// Set token lifetime
if inputs.TokenLifetime <= 0 {
api.TokenLifetime = auth0.Int(apiDefaultTokenLifetime())
api.TokenLifetime = auth0.Int(apiDefaultTokenLifetime)
} else {
api.TokenLifetime = auth0.Int(inputs.TokenLifetime)
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Create(cmd.Context(), api)
}); err != nil {
return fmt.Errorf("An unexpected error occurred while attempting to create an API with name '%s' and identifier '%s': %w", inputs.Name, inputs.Identifier, err)
return fmt.Errorf(
"failed to create an API with name '%s' and identifier '%s': %w",
inputs.Name,
inputs.Identifier,
err,
)
}

cli.renderer.APICreate(api)

return nil
},
}
Expand All @@ -278,6 +297,7 @@ func createAPICmd(cli *cli) *cobra.Command {
apiScopes.RegisterStringSlice(cmd, &inputs.Scopes, nil)
apiOfflineAccess.RegisterBool(cmd, &inputs.AllowOfflineAccess, false)
apiTokenLifetime.RegisterInt(cmd, &inputs.TokenLifetime, 0)
apiSigningAlgorithm.RegisterString(cmd, &inputs.SigningAlgorithm, "RS256")

return cmd
}
Expand All @@ -289,6 +309,7 @@ func updateAPICmd(cli *cli) *cobra.Command {
Scopes []string
TokenLifetime int
AllowOfflineAccess bool
SigningAlgorithm string
}

cmd := &cobra.Command{
Expand All @@ -304,26 +325,23 @@ func updateAPICmd(cli *cli) *cobra.Command {
auth0 apis update <api-id|api-audience> --name myapi
auth0 apis update <api-id|api-audience> --name myapi --token-lifetime 6100
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"
auth0 apis update <api-id|api-audience> -n myapi -t 6100 -o false -s "letter:write,letter:read" --json`,
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`,
RunE: func(cmd *cobra.Command, args []string) error {
var current *management.ResourceServer

if len(args) == 0 {
err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions)
if err != nil {
if err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions); err != nil {
return err
}
} else {
inputs.ID = args[0]
}

if err := ansi.Waiting(func() error {
var err error
current, err = cli.api.ResourceServer.Read(cmd.Context(), url.PathEscape(inputs.ID))
var current *management.ResourceServer
if err := ansi.Waiting(func() (err error) {
current, err = cli.api.ResourceServer.Read(cmd.Context(), inputs.ID)
return err
}); err != nil {
return fmt.Errorf("Unable to load API: %w", err)
return fmt.Errorf("failed to find API with ID %q: %w", inputs.ID, err)
}

if err := apiName.AskU(cmd, &inputs.Name, current.Name); err != nil {
Expand All @@ -334,48 +352,55 @@ func updateAPICmd(cli *cli) *cobra.Command {
return err
}

currentTokenLifetime := strconv.Itoa(auth0.IntValue(current.TokenLifetime))
if err := apiTokenLifetime.AskU(cmd, &inputs.TokenLifetime, &currentTokenLifetime); err != nil {
currentTokenLifetime := strconv.Itoa(current.GetTokenLifetime())
if err := apiTokenLifetime.AskIntU(cmd, &inputs.TokenLifetime, &currentTokenLifetime); err != nil {
return err
}

if !apiOfflineAccess.IsSet(cmd) {
inputs.AllowOfflineAccess = auth0.BoolValue(current.AllowOfflineAccess)
inputs.AllowOfflineAccess = current.GetAllowOfflineAccess()
}

if err := apiOfflineAccess.AskBoolU(cmd, &inputs.AllowOfflineAccess, current.AllowOfflineAccess); err != nil {
return err
}

if err := apiSigningAlgorithm.AskU(cmd, &inputs.SigningAlgorithm, current.SigningAlgorithm); err != nil {
return err
}

api := &management.ResourceServer{
AllowOfflineAccess: &inputs.AllowOfflineAccess,
}

if len(inputs.Name) == 0 {
api.Name = current.Name
} else {
api.Name = current.Name
if len(inputs.Name) != 0 {
api.Name = &inputs.Name
}

if len(inputs.Scopes) == 0 {
api.Scopes = current.Scopes
} else {
api.Scopes = current.Scopes
if len(inputs.Scopes) != 0 {
api.Scopes = apiScopesFor(inputs.Scopes)
}

if inputs.TokenLifetime == 0 {
api.TokenLifetime = current.TokenLifetime
} else {
api.TokenLifetime = current.TokenLifetime
if inputs.TokenLifetime != 0 {
api.TokenLifetime = &inputs.TokenLifetime
}

api.SigningAlgorithm = current.SigningAlgorithm
if inputs.SigningAlgorithm != "" {
api.SigningAlgorithm = &inputs.SigningAlgorithm
}

if err := ansi.Waiting(func() error {
return cli.api.ResourceServer.Update(cmd.Context(), current.GetID(), api)
}); err != nil {
return fmt.Errorf("An unexpected error occurred while trying to update an API with Id '%s': %w", inputs.ID, err)
return fmt.Errorf("failed to update the API with ID %q: %w", inputs.ID, err)
}

cli.renderer.APIUpdate(api)

return nil
},
}
Expand All @@ -385,6 +410,7 @@ func updateAPICmd(cli *cli) *cobra.Command {
apiScopes.RegisterStringSliceU(cmd, &inputs.Scopes, nil)
apiOfflineAccess.RegisterBoolU(cmd, &inputs.AllowOfflineAccess, false)
apiTokenLifetime.RegisterIntU(cmd, &inputs.TokenLifetime, 0)
apiSigningAlgorithm.RegisterStringU(cmd, &inputs.SigningAlgorithm, "RS256")

return cmd
}
Expand Down Expand Up @@ -550,10 +576,6 @@ func apiScopesFor(scopes []string) *[]management.ResourceServerScope {
return &models
}

func apiDefaultTokenLifetime() int {
return 86400
}

func (c *cli) apiPickerOptions(ctx context.Context) (pickerOptions, error) {
return c.filteredAPIPickerOptions(ctx, func(r *management.ResourceServer) bool {
return true
Expand Down
30 changes: 16 additions & 14 deletions internal/display/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
)

type apiView struct {
ID string
Name string
Identifier string
Scopes string
TokenLifetime int
OfflineAccess string
ID string
Name string
Identifier string
Scopes string
TokenLifetime int
OfflineAccess string
SigningAlgorithm string

raw interface{}
}
Expand All @@ -39,6 +40,7 @@ func (v *apiView) KeyValues() [][]string {
{"SCOPES", v.Scopes},
{"TOKEN LIFETIME", strconv.Itoa(v.TokenLifetime)},
{"ALLOW OFFLINE ACCESS", v.OfflineAccess},
{"SIGNING ALGORITHM", v.SigningAlgorithm},
}
}

Expand Down Expand Up @@ -111,14 +113,14 @@ func (r *Renderer) APIUpdate(api *management.ResourceServer) {
func makeAPIView(api *management.ResourceServer) (*apiView, bool) {
scopes, scopesTruncated := getScopes(api.GetScopes())
view := &apiView{
ID: ansi.Faint(api.GetID()),
Name: api.GetName(),
Identifier: api.GetIdentifier(),
Scopes: scopes,
TokenLifetime: api.GetTokenLifetime(),
OfflineAccess: boolean(api.GetAllowOfflineAccess()),

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(),
raw: api,
}
return view, scopesTruncated
}
Expand Down
13 changes: 11 additions & 2 deletions test/integration/apis-test-cases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ 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 --json
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:
Expand All @@ -31,9 +31,10 @@ tests:
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
command: auth0 apis create --name integration-test-api-def2 --identifier http://integration-test-api-def2 --scopes read:todos,write:todos --signing-alg RS256
exit-code: 0
stdout:
contains:
Expand All @@ -42,6 +43,7 @@ tests:
- SCOPES read:todos write:todos
- TOKEN LIFETIME 86400
- ALLOW OFFLINE ACCESS ✗
- SIGNING ALGORITHM RS256

# Test 'apis create' --token-lifetime flag
005 - apis create token lifetime 1000 and check data:
Expand Down Expand Up @@ -142,6 +144,13 @@ tests:
allow_offline_access: "false"
exit-code: 0

018 - apis update signing algorithm:
command: auth0 apis update $(./test/integration/scripts/get-api-id.sh) --signing-alg=HS256 --json
stdout:
json:
signing_alg: "HS256"
exit-code: 0

018 - it successfully prints out a URL to open:
command: auth0 apis open $(./test/integration/scripts/get-api-id.sh) --no-input
exit-code: 0
Expand Down

0 comments on commit fd9092c

Please sign in to comment.