From 8489705345a4eeefd01455e4fd324d7eedc3a32a Mon Sep 17 00:00:00 2001 From: Milan Jevgenijevic Date: Tue, 3 Feb 2026 16:06:16 +0100 Subject: [PATCH 1/4] feat: added dynamic client registration --- cmd/dcr.go | 19 +++++++++++++++++ cmd/dcr/register.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 11 +--------- 3 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 cmd/dcr.go create mode 100644 cmd/dcr/register.go diff --git a/cmd/dcr.go b/cmd/dcr.go new file mode 100644 index 0000000..9cd590a --- /dev/null +++ b/cmd/dcr.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/adobe/imscli/cmd/dcr" + "github.com/adobe/imscli/ims" + "github.com/spf13/cobra" +) + +func dcrCmd(imsConfig *ims.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "dcr", + Short: "Dynamic Client Registration operations.", + Long: `The dcr command enables Dynamic Client Registration operations.`, + } + cmd.AddCommand( + dcr.RegisterCmd(imsConfig), + ) + return cmd +} diff --git a/cmd/dcr/register.go b/cmd/dcr/register.go new file mode 100644 index 0000000..c3a3ab3 --- /dev/null +++ b/cmd/dcr/register.go @@ -0,0 +1,52 @@ +package dcr + +import ( + "fmt" + "io" + "net/http" + "strings" + + "github.com/adobe/imscli/ims" + "github.com/spf13/cobra" +) + +func RegisterCmd(imsConfig *ims.Config) *cobra.Command { + var registerURL, clientName string + var redirectURIs []string + + cmd := &cobra.Command{ + Use: "register", + Short: "Register a dynamic client.", + Long: `Register a new OAuth 2.0 client dynamically using OIDC Dynamic Client Registration.`, + RunE: func(cmd *cobra.Command, args []string) error { + // Build redirect URIs JSON array + redirectURIsJSON := "[" + for i, uri := range redirectURIs { + if i > 0 { + redirectURIsJSON += "," + } + redirectURIsJSON += fmt.Sprintf(`"%s"`, uri) + } + redirectURIsJSON += "]" + + payload := strings.NewReader(fmt.Sprintf(`{ + "client_name": "%s", + "redirect_uris": %s +}`, clientName, redirectURIsJSON)) + req, _ := http.NewRequest("POST", registerURL, payload) + req.Header.Add("content-type", "application/json") + res, _ := http.DefaultClient.Do(req) + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + fmt.Println(res) + fmt.Println(string(body)) + return nil + }, + } + + cmd.Flags().StringVarP(®isterURL, "url", "u", "", "OIDC registration endpoint URL.") + cmd.Flags().StringVarP(&clientName, "clientName", "n", "", "Client application name.") + cmd.Flags().StringSliceVarP(&redirectURIs, "redirectURIs", "r", []string{}, "Redirect URIs (comma-separated or multiple flags).") + + return cmd +} diff --git a/cmd/root.go b/cmd/root.go index 4e0004e..7c7813c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,13 +1,3 @@ -// Copyright 2020 Adobe. All rights reserved. -// This file is licensed to you under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy -// of the License at http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software distributed under -// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS -// OF ANY KIND, either express or implied. See the License for the specific language -// governing permissions and limitations under the License. - package cmd import ( @@ -55,6 +45,7 @@ func RootCmd(version string) *cobra.Command { decodeCmd(imsConfig), refreshCmd(imsConfig), adminCmd(imsConfig), + dcrCmd(imsConfig), ) return cmd } From 2191cf42543be0f00d001a6534bae95a942c71a8 Mon Sep 17 00:00:00 2001 From: Milan Jevgenijevic Date: Tue, 3 Feb 2026 17:22:50 +0100 Subject: [PATCH 2/4] feat: added dynamic client registration --- cmd/root.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 7c7813c..85a3a02 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,3 +1,13 @@ +// Copyright 2020 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy +// of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under +// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +// OF ANY KIND, either express or implied. See the License for the specific language +// governing permissions and limitations under the License. + package cmd import ( From a19faf8934f6373bfd4a1bd4791f4c0515ceab00 Mon Sep 17 00:00:00 2001 From: Milan Jevgenijevic Date: Wed, 4 Feb 2026 11:02:49 +0100 Subject: [PATCH 3/4] fix: moved register.go to /ims and dialogu fixes --- cmd/dcr.go | 3 +-- {cmd/dcr => ims}/register.go | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) rename {cmd/dcr => ims}/register.go (77%) diff --git a/cmd/dcr.go b/cmd/dcr.go index 9cd590a..a932652 100644 --- a/cmd/dcr.go +++ b/cmd/dcr.go @@ -1,7 +1,6 @@ package cmd import ( - "github.com/adobe/imscli/cmd/dcr" "github.com/adobe/imscli/ims" "github.com/spf13/cobra" ) @@ -13,7 +12,7 @@ func dcrCmd(imsConfig *ims.Config) *cobra.Command { Long: `The dcr command enables Dynamic Client Registration operations.`, } cmd.AddCommand( - dcr.RegisterCmd(imsConfig), + ims.RegisterCmd(imsConfig), ) return cmd } diff --git a/cmd/dcr/register.go b/ims/register.go similarity index 77% rename from cmd/dcr/register.go rename to ims/register.go index c3a3ab3..288b7ec 100644 --- a/cmd/dcr/register.go +++ b/ims/register.go @@ -1,4 +1,4 @@ -package dcr +package ims import ( "fmt" @@ -6,18 +6,17 @@ import ( "net/http" "strings" - "github.com/adobe/imscli/ims" "github.com/spf13/cobra" ) -func RegisterCmd(imsConfig *ims.Config) *cobra.Command { +func RegisterCmd(imsConfig *Config) *cobra.Command { var registerURL, clientName string var redirectURIs []string cmd := &cobra.Command{ Use: "register", - Short: "Register a dynamic client.", - Long: `Register a new OAuth 2.0 client dynamically using OIDC Dynamic Client Registration.`, + Short: "Register a client.", + Long: `Register a new OAuth client using Dynamic Client Registration.`, RunE: func(cmd *cobra.Command, args []string) error { // Build redirect URIs JSON array redirectURIsJSON := "[" @@ -44,7 +43,7 @@ func RegisterCmd(imsConfig *ims.Config) *cobra.Command { }, } - cmd.Flags().StringVarP(®isterURL, "url", "u", "", "OIDC registration endpoint URL.") + cmd.Flags().StringVarP(®isterURL, "url", "u", "", "registration endpoint URL.") cmd.Flags().StringVarP(&clientName, "clientName", "n", "", "Client application name.") cmd.Flags().StringSliceVarP(&redirectURIs, "redirectURIs", "r", []string{}, "Redirect URIs (comma-separated or multiple flags).") From a79106a997734dbbf8c016e55c1c55bb95797d98 Mon Sep 17 00:00:00 2001 From: Milan Jevgenijevic Date: Wed, 11 Feb 2026 12:51:34 +0100 Subject: [PATCH 4/4] fix: made the code structure fit the other files in the project --- cmd/dcr.go | 31 ++++++++++++++++- ims/config.go | 3 ++ ims/register.go | 92 ++++++++++++++++++++++++++++++------------------- 3 files changed, 89 insertions(+), 37 deletions(-) diff --git a/cmd/dcr.go b/cmd/dcr.go index a932652..1516fea 100644 --- a/cmd/dcr.go +++ b/cmd/dcr.go @@ -1,6 +1,8 @@ package cmd import ( + "fmt" + "github.com/adobe/imscli/ims" "github.com/spf13/cobra" ) @@ -12,7 +14,34 @@ func dcrCmd(imsConfig *ims.Config) *cobra.Command { Long: `The dcr command enables Dynamic Client Registration operations.`, } cmd.AddCommand( - ims.RegisterCmd(imsConfig), + registerCmd(imsConfig), ) return cmd } + +func registerCmd(imsConfig *ims.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "register", + Short: "Register a client.", + Long: `Register a new OAuth client using Dynamic Client Registration.`, + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + cmd.SilenceErrors = true + + resp, err := imsConfig.Register() + if err != nil { + return fmt.Errorf("error during client registration: %v", err) + } + + fmt.Printf("Status Code: %d\n", resp.StatusCode) + fmt.Println(resp.Body) + return nil + }, + } + + cmd.Flags().StringVarP(&imsConfig.RegisterURL, "url", "u", "", "Registration endpoint URL.") + cmd.Flags().StringVarP(&imsConfig.ClientName, "clientName", "n", "", "Client application name.") + cmd.Flags().StringSliceVarP(&imsConfig.RedirectURIs, "redirectURIs", "r", []string{}, "Redirect URIs (comma-separated or multiple flags).") + + return cmd +} diff --git a/ims/config.go b/ims/config.go index 4b8e196..b54bff0 100644 --- a/ims/config.go +++ b/ims/config.go @@ -43,6 +43,9 @@ type Config struct { Guid string AuthSrc string DecodeFulfillableData bool + RegisterURL string + ClientName string + RedirectURIs []string } // Access token information diff --git a/ims/register.go b/ims/register.go index 288b7ec..88e94d8 100644 --- a/ims/register.go +++ b/ims/register.go @@ -5,47 +5,67 @@ import ( "io" "net/http" "strings" - - "github.com/spf13/cobra" ) -func RegisterCmd(imsConfig *Config) *cobra.Command { - var registerURL, clientName string - var redirectURIs []string - - cmd := &cobra.Command{ - Use: "register", - Short: "Register a client.", - Long: `Register a new OAuth client using Dynamic Client Registration.`, - RunE: func(cmd *cobra.Command, args []string) error { - // Build redirect URIs JSON array - redirectURIsJSON := "[" - for i, uri := range redirectURIs { - if i > 0 { - redirectURIsJSON += "," - } - redirectURIsJSON += fmt.Sprintf(`"%s"`, uri) - } - redirectURIsJSON += "]" - - payload := strings.NewReader(fmt.Sprintf(`{ +// RegisterResponse contains the response from DCR registration +type RegisterResponse struct { + StatusCode int + Body string +} + +func (i Config) validateRegisterConfig() error { + switch { + case i.RegisterURL == "": + return fmt.Errorf("missing registration endpoint URL parameter") + case i.ClientName == "": + return fmt.Errorf("missing client name parameter") + case len(i.RedirectURIs) == 0: + return fmt.Errorf("missing redirect URIs parameter") + default: + return nil + } +} + +// Register performs Dynamic Client Registration +func (i Config) Register() (RegisterResponse, error) { + if err := i.validateRegisterConfig(); err != nil { + return RegisterResponse{}, fmt.Errorf("invalid parameters for client registration: %v", err) + } + + // Build redirect URIs JSON array + redirectURIsJSON := "[" + for idx, uri := range i.RedirectURIs { + if idx > 0 { + redirectURIsJSON += "," + } + redirectURIsJSON += fmt.Sprintf(`"%s"`, uri) + } + redirectURIsJSON += "]" + + payload := strings.NewReader(fmt.Sprintf(`{ "client_name": "%s", "redirect_uris": %s -}`, clientName, redirectURIsJSON)) - req, _ := http.NewRequest("POST", registerURL, payload) - req.Header.Add("content-type", "application/json") - res, _ := http.DefaultClient.Do(req) - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - fmt.Println(res) - fmt.Println(string(body)) - return nil - }, +}`, i.ClientName, redirectURIsJSON)) + + req, err := http.NewRequest("POST", i.RegisterURL, payload) + if err != nil { + return RegisterResponse{}, fmt.Errorf("error creating request: %v", err) } + req.Header.Add("content-type", "application/json") - cmd.Flags().StringVarP(®isterURL, "url", "u", "", "registration endpoint URL.") - cmd.Flags().StringVarP(&clientName, "clientName", "n", "", "Client application name.") - cmd.Flags().StringSliceVarP(&redirectURIs, "redirectURIs", "r", []string{}, "Redirect URIs (comma-separated or multiple flags).") + res, err := http.DefaultClient.Do(req) + if err != nil { + return RegisterResponse{}, fmt.Errorf("error making registration request: %v", err) + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return RegisterResponse{}, fmt.Errorf("error reading response body: %v", err) + } - return cmd + return RegisterResponse{ + StatusCode: res.StatusCode, + Body: string(body), + }, nil }