Skip to content

Commit

Permalink
Add new "refresh" command (#20)
Browse files Browse the repository at this point in the history
* Initial implementation of token refresh

* Update dependencies

* Add full output to show refresh token
  • Loading branch information
telegrapher authored Sep 18, 2023
1 parent b808561 commit cd0e29b
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 3 deletions.
61 changes: 61 additions & 0 deletions cmd/refresh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2021 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 (
"encoding/json"
"fmt"

"github.com/adobe/imscli/ims"
"github.com/spf13/cobra"
)

func refreshCmd(imsConfig *ims.Config) *cobra.Command {
cmd := &cobra.Command{
Use: "refresh",
Aliases: []string{"exch"},
Short: "Exchange a refresh token for new access and refresh tokens.",
Long: "Exchange a refresh token for new access and refresh tokens.",
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
cmd.SilenceErrors = true

resp, err := imsConfig.Refresh()
if err != nil {
return fmt.Errorf("error during the token refresh: %v", err)
}
if imsConfig.FullOutput {
data := map[string]interface{}{
"access_token": resp.AccessToken,
"refresh_token": resp.RefreshToken,
}
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
return fmt.Errorf("error marshalling full JSON response: %v", err)
}
fmt.Printf("%s", jsonData)
return nil
}
fmt.Println(resp.AccessToken)
return nil
},
}

cmd.Flags().StringVarP(&imsConfig.ClientID, "clientID", "c", "", "IMS client ID.")
cmd.Flags().StringVarP(&imsConfig.ClientSecret, "clientSecret", "p", "", "IMS client secret.")
cmd.Flags().StringVarP(&imsConfig.RefreshToken, "refreshToken", "t", "", "Refresh token.")
cmd.Flags().StringSliceVarP(&imsConfig.Scopes, "scopes", "s", []string{""},
"Scopes to request in the new token. Subset of the scopes of the original token. Optional value, if no "+
"scopes are requested the same scopes of the original token will be provided.")
cmd.Flags().BoolVarP(&imsConfig.FullOutput, "fullOutput", "F", false, "Output a JSON with access and refresh tokens.")

return cmd
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func RootCmd(version string) *cobra.Command {
exchangeCmd(imsConfig),
invalidateCmd(imsConfig),
decodeCmd(imsConfig),
refreshCmd(imsConfig),
)
return cmd
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module github.com/adobe/imscli
go 1.19

require (
github.com/adobe/ims-go v0.15.0
github.com/adobe/ims-go v0.16.1
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
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/adobe/ims-go v0.15.0 h1:OIKqlBO04JI/+7jEp6g1jBvm9B1v4Uk/bYt68+GVZdw=
github.com/adobe/ims-go v0.15.0/go.mod h1:nsvzRhDFespyZnnLxQlsfBmlfGzqcy/zuS2HGebDHMI=
github.com/adobe/ims-go v0.16.1 h1:n1gYlfAV9djx9+r9VGU8I49G8fnIrIsZvX1s/XJVD3w=
github.com/adobe/ims-go v0.16.1/go.mod h1:nsvzRhDFespyZnnLxQlsfBmlfGzqcy/zuS2HGebDHMI=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand Down
7 changes: 7 additions & 0 deletions ims/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ type Config struct {
Token string
Port int
PKCE bool
FullOutput bool
}

// Access token information
type TokenInfo struct {
AccessToken string
Expires int //(response.ExpiresIn * time.Millisecond),
Valid bool
Info string
}

type RefreshInfo struct {
TokenInfo
RefreshToken string
}

func validateURL(u string) bool {
parsedURL, err := url.Parse(u)
if err != nil {
Expand Down
71 changes: 71 additions & 0 deletions ims/refresh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2021 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 ims

import (
"fmt"
"github.com/adobe/ims-go/ims"
"time"
)

func (i Config) validateRefreshConfig() error {
switch {
case i.URL == "":
return fmt.Errorf("missing IMS base URL parameter")
case i.ClientID == "":
return fmt.Errorf("missing client ID parameter")
case i.ClientSecret == "":
return fmt.Errorf("missing client secret parameter")
case i.RefreshToken == "":
return fmt.Errorf("missing refresh token parameter")
default:
return nil
}
}

// Refresh performs the refresh token flow.
func (i Config) Refresh() (RefreshInfo, error) {

if err := i.validateRefreshConfig(); err != nil {
return RefreshInfo{}, fmt.Errorf("invalid parameters for token refresh: %v", err)
}

httpClient, err := i.httpClient()
if err != nil {
return RefreshInfo{}, fmt.Errorf("error creating the HTTP Client: %v", err)
}

c, err := ims.NewClient(&ims.ClientConfig{
URL: i.URL,
Client: httpClient,
})
if err != nil {
return RefreshInfo{}, fmt.Errorf("create client: %v", err)
}

r, err := c.RefreshToken(&ims.RefreshTokenRequest{
ClientID: i.ClientID,
ClientSecret: i.ClientSecret,
RefreshToken: i.RefreshToken,
Scope: i.Scopes,
})
if err != nil {
return RefreshInfo{}, fmt.Errorf("error during the token refresh: %v", err)
}

return RefreshInfo{
TokenInfo: TokenInfo{
AccessToken: r.AccessToken,
Expires: int(r.ExpiresIn * time.Second),
},
RefreshToken: r.RefreshToken,
}, nil
}

0 comments on commit cd0e29b

Please sign in to comment.