Skip to content

Commit

Permalink
feat: auth0 clients create improvements (#44)
Browse files Browse the repository at this point in the history
* feat (wip) adding auth method

* feat: prompt for type and desc

* feat: prompt desc and type

* fix: show secret if not native or SPA app

* feat: add quickstarts

* tidy
  • Loading branch information
jfatta authored Jan 26, 2021
1 parent e82a765 commit ab2942a
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 22 deletions.
6 changes: 5 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey v1.8.8 h1:Y4yypp763E8cbqb5RBqZhGgkCFLRFnbRBHrxnpMMsgQ=
github.com/AlecAivazis/survey/v2 v2.2.7 h1:5NbxkF4RSKmpywYdcRgUmos1o+roJY8duCLZXbVjoig=
github.com/AlecAivazis/survey/v2 v2.2.7/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/rehttp v1.0.0 h1:aJ7A7YI2lIvOxcJVeUZY4P6R7kKZtLeONjgyKGwOIu8=
Expand Down Expand Up @@ -152,6 +152,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
Expand All @@ -166,8 +167,10 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
Expand Down Expand Up @@ -502,6 +505,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
Expand Down
110 changes: 89 additions & 21 deletions internal/cli/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/auth0/auth0-cli/internal/ansi"
"github.com/auth0/auth0-cli/internal/auth0"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -53,11 +54,11 @@ Lists your existing clients. To create one try:

func clientsCreateCmd(cli *cli) *cobra.Command {
var flags struct {
name string
appType string
description string
reveal bool
callbacks []string
Name string
AppType string
Description string
Callbacks []string
TokenEndpointAuthMethod string
}
cmd := &cobra.Command{
Use: "create",
Expand All @@ -73,13 +74,67 @@ auth0 clients create --name myapp --type [native|spa|regular|m2m]
- m2m (machine to machine): CLIs, daemons or services running on your backend.
`,
RunE: func(cmd *cobra.Command, args []string) error {
// TODO(jfatta): depending on the app type, other client properties might be mandatory
// check: create app dashboard
// todo(jfatta) on non-interactive the cmd should fail on missing mandatory args (name, type)
if !cmd.Flags().Changed("name") {
qs := []*survey.Question{
{
Name: "Name",
Prompt: &survey.Input{
Message: "Name:",
Default: "My App",
Help: "Name of the client (also known as application). You can change the application name later in the application settings.",
},
},
}

err := survey.Ask(qs, &flags)
if err != nil {
return err
}
}

if !cmd.Flags().Changed("type") {
qs := []*survey.Question{
{
Name: "AppType",
Prompt: &survey.Select{
Message: "Type:",
Help: "\n- Native: Mobile, desktop, CLI and smart device apps running natively." +
"\n- Single Page Web Application: A JavaScript front-end app that uses an API." +
"\n- Regular Web Application: Traditional web app using redirects." +
"\n- Machine To Machine: CLIs, daemons or services running on your backend.",
Options: []string{"Native", "Single Page Web Application", "Regular Web Application", "Machine to Machine"},
},
},
}
err := survey.Ask(qs, &flags)
if err != nil {
return err
}
}

if !cmd.Flags().Changed("description") {
qs := []*survey.Question{
{
Name: "Description",
Prompt: &survey.Input{
Message: "Description:",
Help: "A free text description of the application.",
},
},
}
err := survey.Ask(qs, &flags)
if err != nil {
return err
}
}

c := &management.Client{
Name: &flags.name,
Description: &flags.description,
AppType: auth0.String(apiAppTypeFor(flags.appType)),
Callbacks: apiCallbacksFor(flags.callbacks),
Name: &flags.Name,
Description: &flags.Description,
AppType: auth0.String(apiAppTypeFor(flags.AppType)),
Callbacks: apiCallbacksFor(flags.Callbacks),
TokenEndpointAuthMethod: apiTokenEndpointAuthMethodFor(flags.TokenEndpointAuthMethod),
}

err := ansi.Spinner("Creating client", func() error {
Expand All @@ -91,17 +146,17 @@ auth0 clients create --name myapp --type [native|spa|regular|m2m]
}

// note: c is populated with the rest of the client fields by the API during creation.
cli.renderer.ClientCreate(c, flags.reveal)
revealClientSecret := auth0.StringValue(c.AppType) != "native" && auth0.StringValue(c.AppType) != "spa"
cli.renderer.ClientCreate(c, revealClientSecret)
return nil
},
}
cmd.Flags().StringVarP(&flags.name, "name", "n", "", "Name of the client.")
cmd.Flags().StringVarP(&flags.appType, "type", "t", "", "Type of the client: native, spa, regular, or m2m.")
cmd.Flags().StringVarP(&flags.description, "description", "d", "", "A free text description of the application. Max character count is 140.")
cmd.Flags().BoolVarP(&flags.reveal, "reveal", "r", false, "⚠️ Reveal the SECRET of the created client.")
cmd.Flags().StringSliceVarP(&flags.callbacks, "callbacks", "c", nil, "After the user authenticates we will only call back to any of these URLs. You can specify multiple valid URLs by comma-separating them (typically to handle different environments like QA or testing). Make sure to specify the protocol (https://) otherwise the callback may fail in some cases. With the exception of custom URI schemes for native clients, all callbacks should use protocol https://.")
cmd.Flags().StringVarP(&flags.Name, "name", "n", "", "Name of the client.")
cmd.Flags().StringVarP(&flags.AppType, "type", "t", "", "Type of the client: native, spa, regular, or m2m.")
cmd.Flags().StringVarP(&flags.Description, "description", "d", "", "A free text description of the application. Max character count is 140.")
cmd.Flags().StringSliceVarP(&flags.Callbacks, "callbacks", "c", nil, "After the user authenticates we will only call back to any of these URLs. You can specify multiple valid URLs by comma-separating them (typically to handle different environments like QA or testing). Make sure to specify the protocol (https://) otherwise the callback may fail in some cases. With the exception of custom URI schemes for native clients, all callbacks should use protocol https://.")

mustRequireFlags(cmd, "name", "type")
cmd.Flags().StringVar(&flags.TokenEndpointAuthMethod, "auth-method", "", "Defines the requested authentication method for the token endpoint. Possible values are 'None' (public application without a client secret), 'Post' (application uses HTTP POST parameters) or 'Basic' (application uses HTTP Basic).")

return cmd
}
Expand All @@ -110,11 +165,11 @@ func apiAppTypeFor(v string) string {
switch strings.ToLower(v) {
case "native":
return "native"
case "spa":
case "spa", "single page web application":
return "spa"
case "regular":
case "regular", "regular web application":
return "regular_web"
case "m2m":
case "m2m", "machine to machine":
return "non_interactive"

default:
Expand All @@ -130,3 +185,16 @@ func apiCallbacksFor(s []string) []interface{} {
return res

}

func apiTokenEndpointAuthMethodFor(v string) *string {
switch strings.ToLower(v) {
case "none":
return auth0.String("none")
case "post":
return auth0.String("client_secret_post")
case "basic":
return auth0.String("client_secret_basic")
default:
return nil
}
}
25 changes: 25 additions & 0 deletions internal/display/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import (
"gopkg.in/auth0.v5/management"
)

const (
quickstartsNative = "https://auth0.com/docs/quickstart/native"
quickstartsSPA = "https://auth0.com/docs/quickstart/spa"
quickstartsRegularWeb = "https://auth0.com/docs/quickstart/webapp"
quickstartsM2M = "https://auth0.com/docs/quickstart/backend"
quickstartsGeneric = "https://auth0.com/docs/quickstarts"
)

type clientView struct {
Name string
Type string
Expand Down Expand Up @@ -79,6 +87,8 @@ func (r *Renderer) ClientCreate(client *management.Client, revealSecrets bool) {
}

r.Results([]View{v})

r.Infof("\nQuickstarts: %s", quickstartsURIFor(client.AppType))
}

// TODO(cyx): determine if there's a better way to filter this out.
Expand Down Expand Up @@ -106,6 +116,21 @@ func appTypeFor(v *string) string {
}
}

func quickstartsURIFor(v *string) string {
switch {
case *v == "native":
return quickstartsNative
case *v == "spa":
return quickstartsSPA
case *v == "regular_web":
return quickstartsRegularWeb
case *v == "non_interactive":
return quickstartsM2M
default:
return quickstartsGeneric
}
}

func callbacksFor(s []interface{}) []string {
res := make([]string, len(s))
for i, v := range s {
Expand Down

0 comments on commit ab2942a

Please sign in to comment.