Skip to content

Commit

Permalink
Switch to preferred AuthN mechanism (#23)
Browse files Browse the repository at this point in the history
## Description Of Change

This PR helps:

* Update BuildJWT logic to handle \n chars that can get added while
copy/pasting the api private key into example code.
* Update examples to use apiKeyName and apiPrivateKey instead of reading
from a api key file.
* Update `README.md` with new preferred auth mechanism.

## Testing Procedure

<!-- Describe how this change has been verified. Either via new
automated tests or manual testing -->

1. Visually inspected the README
2. Ran through the quick start guide to make sure it's working
  • Loading branch information
drohit-cb authored May 10, 2024
1 parent e63f4af commit ea13117
Show file tree
Hide file tree
Showing 15 changed files with 117 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.0
0.6.0
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ A traditional infrastructure-heavy staking integration can take months. Coinbase
Prerequisite: [Go 1.21+](https://go.dev/doc/install)

1. In a fresh directory, copy and paste one of the code samples below or any of our [provided examples](./examples) into an `example.go` file.
2. Create and download an API key from the [Cloud Platform](https://portal.cloud.coinbase.com/access/api).
3. Place the key named `.coinbase_cloud_api_key.json` at the root of your repository.
4. Setup a Go project and run the example :rocket:

2. Create a new API Key in the [portal](https://portal.cdp.coinbase.com/access/api) and paste the `apiKeyName` and `apiPrivateKey` into the `example.go` file.

3. Setup a Go project and run the example :rocket:

```shell
go mod init example
Expand Down Expand Up @@ -52,11 +53,16 @@ import (
api "github.com/coinbase/staking-client-library-go/gen/go/coinbase/staking/orchestration/v1"
)
var (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
)
func main() {
ctx := context.Background()
// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}
Expand Down Expand Up @@ -159,13 +165,18 @@ import (
api "github.com/coinbase/staking-client-library-go/gen/go/coinbase/staking/orchestration/v1"
)
var (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
)
func main() {
ctx := context.Background()
// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
log.Fatalf("error loading API key: %s", err.Error())
}
// Creates the Coinbase Staking API client.
Expand Down Expand Up @@ -273,17 +284,20 @@ import (
)
const (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
// https://beaconcha.in/validator/1
address = "0xa1d1ad0714035353258038e964ae9675dc0252ee22cea896825c01458e1807bfad2f9969338798548d9858a571f7425c"
)
func main() {
ctx := context.Background()
// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
log.Fatalf("error loading API key: %s", err.Error())
}
// Creates the Coinbase Staking API client
Expand Down Expand Up @@ -388,7 +402,7 @@ func main() {
## Documentation
There are numerous examples in the [`examples directory`](./examples) to help get you started. For even more, refer to our [documentation website](https://docs.cdp.coinbase.com/staking/docs/welcome) for detailed definitions, API specifications, integration guides, and more!
There are numerous examples in the [`examples directory`](./examples) to help get you started. For even more, refer to our [documentation website](https://docs.cdp.coinbase.com/staking/docs/welcome) for detailed definitions, [API specification](https://docs.cdp.coinbase.com/staking/reference), integration guides, and more!
## Contributing
Expand Down
4 changes: 2 additions & 2 deletions auth/api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ func WithLoadAPIKeyFromEnv(loadAPIKeyFromEnv bool) APIKeyOption {
// Key from file directly. If the API Key name and private key are both set,
// they take precedence over the environment variables. Next if the env vars are
// set they take precedence or else the file is used if set.
func WithLoadAPIKeyFromFile(loadAPIKeyFromFile bool) APIKeyOption {
func WithLoadAPIKeyFromFile() APIKeyOption {
return func(t *apiKeyConfig) {
t.loadAPIKeyFromFile = loadAPIKeyFromFile
t.loadAPIKeyFromFile = true
}
}

Expand Down
8 changes: 7 additions & 1 deletion auth/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"math"
"math/big"
"strings"
"time"

"gopkg.in/square/go-jose.v2"
Expand All @@ -33,7 +34,12 @@ func NewAuthenticator(apiKey *APIKey) *Authenticator {

// BuildJWT constructs and returns the JWT as a string along with an error, if any.
func (a *Authenticator) BuildJWT(service, uri string) (string, error) {
block, _ := pem.Decode([]byte(a.apiKey.PrivateKey))
privateKey := a.apiKey.PrivateKey

// Replace escaped newline sequence
privateKey = strings.ReplaceAll(privateKey, "\\n", "\n")

block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return "", fmt.Errorf("could not decode private key")
}
Expand Down
10 changes: 6 additions & 4 deletions examples/cosmos/list-rewards/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,24 @@ import (
*/

const (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"

// https://atomscan.com/validators/cosmosvaloper1crqm3598z6qmyn2kkcl9dz7uqs4qdqnr6s8jdn
address = "cosmos1crqm3598z6qmyn2kkcl9dz7uqs4qdqnrlyn8pq"
)

func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}
Expand Down
10 changes: 6 additions & 4 deletions examples/cosmos/list-stakes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,24 @@ import (
*/

const (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"

// https://atomscan.com/validators/cosmosvaloper1crqm3598z6qmyn2kkcl9dz7uqs4qdqnr6s8jdn
address = "cosmos1crqm3598z6qmyn2kkcl9dz7uqs4qdqnrlyn8pq"
)

func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}
Expand Down
20 changes: 11 additions & 9 deletions examples/ethereum/create-and-process-workflow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import (
)

const (
// TODO: Replace with your private key.
privateKey = ""
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"

// TODO: Replace with your wallet's private key.
walletPrivateKey = ""

// TODO: Replace with your staker addresses and amount.
stakerAddress = ""
Expand All @@ -34,21 +37,20 @@ const (
func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}

if privateKey == "" || stakerAddress == "" {
log.Fatalf("privateKey stakerAddress must be set")
if walletPrivateKey == "" || stakerAddress == "" {
log.Fatalf("walletPrivateKey stakerAddress must be set")
}

req := &api.CreateWorkflowRequest{
Expand Down Expand Up @@ -96,7 +98,7 @@ func main() {
// Logic to sign the transaction. This can be substituted with any other signing mechanism.
log.Printf("Signing unsigned tx %s ...\n", unsignedTx)

signedTx, err := signer.New("ethereum_kiln").SignTransaction([]string{privateKey}, &signer.UnsignedTx{Data: []byte(unsignedTx)})
signedTx, err := signer.New("ethereum_kiln").SignTransaction([]string{walletPrivateKey}, &signer.UnsignedTx{Data: []byte(unsignedTx)})
if err != nil {
log.Fatalf(fmt.Errorf("error signing transaction: %w", err).Error())
}
Expand Down
12 changes: 9 additions & 3 deletions examples/ethereum/create-workflow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@ import (
"context"
"log"

"google.golang.org/protobuf/encoding/protojson"

"github.com/coinbase/staking-client-library-go/auth"
"github.com/coinbase/staking-client-library-go/client"
"github.com/coinbase/staking-client-library-go/client/options"
api "github.com/coinbase/staking-client-library-go/gen/go/coinbase/staking/orchestration/v1"
"google.golang.org/protobuf/encoding/protojson"
)

var (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
)

func main() {
ctx := context.Background()

// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}
Expand Down
7 changes: 5 additions & 2 deletions examples/ethereum/list-rewards/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ import (
*/

const (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"

// https://beaconcha.in/validator/1
address = "0xa1d1ad0714035353258038e964ae9675dc0252ee22cea896825c01458e1807bfad2f9969338798548d9858a571f7425c"
)

func main() {
ctx := context.Background()

// Loads the API key from the default location.
apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}
Expand Down
10 changes: 6 additions & 4 deletions examples/ethereum/list-stakes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,24 @@ import (
*/

const (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"

// https://beaconcha.in/validator/1
address = "0xa1d1ad0714035353258038e964ae9675dc0252ee22cea896825c01458e1807bfad2f9969338798548d9858a571f7425c"
)

func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}
Expand Down
12 changes: 8 additions & 4 deletions examples/hello-world/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ import (
"google.golang.org/api/iterator"
)

var (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
)

// An example function that verifies the API key has been configured correctly and you can connect to the Coinbase Staking API.
func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}
Expand Down
12 changes: 8 additions & 4 deletions examples/list-workflows/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ import (
"google.golang.org/api/iterator"
)

var (
apiKeyName = "your-api-key-name"
apiPrivateKey = "your-api-private-key"
)

// An example function to demonstrate how to use the staking client libraries.
func main() {
ctx := context.Background()

apiKey, err := auth.NewAPIKey(auth.WithLoadAPIKeyFromFile(true))
// Loads the API key.
apiKey, err := auth.NewAPIKey(auth.WithAPIKeyName(apiKeyName, apiPrivateKey))
if err != nil {
log.Fatalf("error loading API key: %s", err.Error())
}

authOpt := options.WithAPIKey(apiKey)

// Create a staking client.
stakingClient, err := client.New(ctx, authOpt)
stakingClient, err := client.New(ctx, options.WithAPIKey(apiKey))
if err != nil {
log.Fatalf("error instantiating staking client: %s", err.Error())
}
Expand Down
Loading

0 comments on commit ea13117

Please sign in to comment.