Skip to content
This repository has been archived by the owner on May 17, 2024. It is now read-only.

Latest commit

 

History

History
318 lines (217 loc) · 9.31 KB

README.md

File metadata and controls

318 lines (217 loc) · 9.31 KB

Track 2.2: Go application

In this track, you will learn how to build a Go application that utilizes Findy Agency API for issuing and verifying credentials.

The application server exposes three endpoints that the web wallet user can utilize to start the interaction with your server. Your task is to implement the functionality for these three endpoints.

Each of these endpoint implementations demonstrate how you can use Findy Agency capabilities. The workshop instructions have detailed instructions how to finalize the implementation.

App Overview

The workshop contains seven tasks:

The assumption is that you work in a guided workshop with the default tooling. In this case, you can skip the sections with the symbol 🤠.

NOTE: The workshop instructions are tested with Linux and MacOS. If you are using Windows, you may encounter problems. In this case, it might be easiest to use a preconfigured environment powered by GitHub Codespaces.

Follow the instructions carefully and execute the tasks in order. Good luck!

Task 0: Setup environment

1. Clone this repository to your workspace

git clone https://github.com/findy-network/agency-workshop.git

2. Install tooling

The recommended tooling for the Go track is to use the Dev Container feature in VS Code.

For the recommended tooling, you need to have the following:

🤠 Other options

You can also set up the tools natively. However, these instructions describe only how to work with the recommended tooling.

If you still wish to go to the wild side, make sure you have these tools available:


3. 🤠 Install Findy Agency

If you are participating in a guided workshop, you will likely have a cloud installation of Findy Agency available. Skip this step.

🤠 Local setup

Start local agency instance if you do not have cloud installation available. See instructions here.


4. Open the Go application in a dev container

Open folder ./track2.2-go/app in VS Code.

VS Code asks if you want to develop the project in a dev container. Click "Reopen in Container."

VS Code Dialog

If you do not see this dialog, activate the dev container menu using the dev container button on the bottom left corner:

VS Code Button

It will take a while for VS Code to pull and set up your dev container. When the process completes, open a new terminal window (Terminal > New terminal).

VS Code Terminal

5. Set environment variables

The agency environment provides a script for automatically setting up the needed environment variables.

Run the following script in the dev container terminal:

source <(curl <agency_url>/set-env.sh)

The agency URL is provided for you in the guided workshop. e.g., https://agency.example.com

🤠 Local setup

For local agency installation, use the web wallet URL http://localhost:3000:

source <(curl http://localhost:3000/set-env.sh)

The script will export the needed environment variables. It will also create a file .envrc that contains these variables. Typing direnv allow will ensure that the variables are automatically exported when you open a new terminal window in this folder.

Script output

🤠 No direnv?

If you don't have direnv installed, you can export the variables by typing source .envrc.


Note! By default, the script will generate a generic username for your client. If you wish to use a more descriptive name for your app, define it before running the script:

export FCLI_USER="my-fancy-issuer-service"

source <(curl <agency_url>/set-env.sh)

The username needs to be unique in the agency context.

6. Start the application

Run the following command:

go run .

When the server is started, VS Code displays a dialog telling where to find the app.

Application running

Click "Open in Browser". The browser should open to URL http://localhost:3001 and display the text "Go example".

Now you have a simple express server running in port 3001 with four endpoints: /, /greet, /issue, and /verify. The next step is to start adding some actual code to the server skeleton.

7. Create the agency connection

Add new dependencies to your project. Type to terminal:

go get github.com/findy-network/findy-agent-auth
go get github.com/findy-network/findy-common-go

findy-agent-auth library has functionality that helps us authenticate to the agency.

findy-common-go library has functionality that helps us control our agent.

Create a new file agent/auth.go.

Add the following content to the new file:

package agent

import (
  "log"
  "os"
  "strconv"

  "github.com/findy-network/findy-agent-auth/acator/authn"
  "github.com/findy-network/findy-common-go/agency/client"
  agency "github.com/findy-network/findy-common-go/grpc/agency/v1"
  "github.com/lainio/err2"
  "github.com/lainio/err2/try"
  "google.golang.org/grpc"
)

const (
  subCmdLogin    = "login"
  subCmdRegister = "register"
)

type AgencyClient struct {
  Conn           client.Conn
  AgentClient    agency.AgentServiceClient
  ProtocolClient agency.ProtocolServiceClient
}

func execAuthCmd(cmd string) (res authn.Result, err error) {
  defer err2.Handle(&err)

  myCmd := authn.Cmd{
    SubCmd:   subCmdLogin,
    UserName: os.Getenv("FCLI_USER"),
    Url:      os.Getenv("FCLI_URL"),
    AAGUID:   "12c85a48-4baf-47bd-b51f-f192871a1511",
    Key:      os.Getenv("FCLI_KEY"),
    Counter:  0,
    Token:    "",
    Origin:   os.Getenv("FCLI_ORIGIN"),
  }

  myCmd.SubCmd = cmd

  try.To(myCmd.Validate())

  return myCmd.Exec(os.Stdout)
}

func LoginAgent() (
  agencyClient *AgencyClient,
  err error,
) {
  defer err2.Handle(&err)

  // first try to login
  res, firstTryErr := execAuthCmd(subCmdLogin)
  if firstTryErr != nil {
    // if login fails, try to register and relogin
    try.To1(execAuthCmd(subCmdRegister))
    res = try.To1(execAuthCmd(subCmdLogin))
  }

  log.Println("Agent login succeeded")

  token := res.Token
  // set up API connection
  conf := client.BuildClientConnBase(
    os.Getenv("FCLI_TLS_PATH"),
    os.Getenv("AGENCY_API_SERVER"),
    try.To1(strconv.Atoi(os.Getenv("AGENCY_API_SERVER_PORT"))),
    []grpc.DialOption{},
  )

  conn := client.TryAuthOpen(token, conf)

  return &AgencyClient{
    Conn:           conn,
    AgentClient:    agency.NewAgentServiceClient(conn),
    ProtocolClient: agency.NewProtocolServiceClient(conn),
  }, nil
}

The LoginAgent function will open a connection to our agent. Through this connection, we can control the agent and listen for any events the agent produces while handling our credential protocol flows.

We authenticate the client using a headless FIDO2 authenticator provided by the agency helper library. When opening the connection for the first time, the functionality in the LoginAgent-function registers the authenticator to our agent.

The FCLI_KEY variable contains the master key to your authenticator. It is generated during the development environment setup. (In production, the key should be naturally generated and handled in a secure manner as a secret). If someone gets access to the key, they can control your agent.

Open file main.go

Add call to LoginAgent to existing main function:

import (

  ...

  "github.com/findy-network/agency-workshop/agent"

  ...

)

func main() {
  defer err2.Catch(err2.Err(func(err error) {
    log.Fatal(err)
  }))

  // Login agent
  try.To1(agent.LoginAgent())

  ...

}

Restart server and verify that you see text "Agent login succeeded": First login log

8. Continue with task 1

Congratulations, you have completed task 0 and have a working agency client development environment available!

You can now continue with task 1.