This is a significant evolution of @blushi’s original Golang-based user-api

The changes are so significant a new repo was created, but a lot of code lives on from that repo.

It builds on that work in several important ways:

  • drops Twirp framework in favour of GRPC-Gateway which has gained significant traction
  • implements full OpenAPIV2 workflow – write interfaces in protobufs and generate the code stubs, then implement them.
  • exposes full Swagger UI automatically
  • implements full RBAC using native Golang Interceptors (arguably better than using Twirp Handlers)
  • RBAC is based on User role and interface access config in the config file
  • built with Go modules for dependency management
  • adds a CLI for database management and for running the server
  • replaces go-pg with bun
  • merges in the models from resonatecoop\id

It is WIP, do NOT use this in Production yet!


Running go run main.go runserver starts a web server on You can configure the port used with the $PORT environment variable, and to serve on HTTP set $SERVE_HTTP=true.

$ go run main.go runserver

An OpenAPI UI is served on

Getting started

After cloning the repo, there are a couple of initial steps;

  1. Ensure that you have Go installed on your system.
  2. Install the generate dependencies with make install. This will install buf, protoc-gen-go, protoc-gen-go-grpc, protoc-gen-grpc-gateway, protoc-gen-openapiv2 and statik which are necessary for us to generate the Go, swagger and static files.
  3. Install the git submodule(s) with git submodule update --init from root directory of the cloned repo
  4. Finally, generate the files with make generate.
  5. Now, you’ll need to generate a certificate:

mkcert -install
mkcert localhost ::1

The certificate is in the directory you ran the above command from. Rename the key file (something like ./ to uaclient.key and the certificate file (something like ./ to uaclient.pem. Copy both of the renamed files to /usr/local/etc/nginx/ssl (if you don’t have an ssl folder in your nginx directory, create one).

Serve the User API at with this command:

UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go runserver -env dev -dbdebug true
  1. Start the server:
pg_ctl -D /usr/local/var/postgres -l logfile start

Dev database setup

  • Create user and database as follows (as found in the local config file in ./conf.local.yaml):

username = “resonate_dev_user”

password = “password”

dbname = “resonate_dev”

To get into the Postgres shell, run:


CREATE DATABASE resonate_dev;
CREATE USER resonate_dev_user WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE resonate_dev TO resonate_dev_user;
  • And add the hstore and uuid-ossp extensions, confirming with the SELECT statement.

\c resonate_dev;
SELECT * FROM pg_extension;
  • Then, run these migrations (from the root of the user-api):

UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go db -env dev init
UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go db -env dev migrate                                                                                                     
UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go db -env dev load_default_fixtures
UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go db -env dev load_test_fixtures
  • Then, repeat the last two above blocks replacing dev with test.

If you need to roll back:

UACERT_DIR="/usr/local/etc/nginx/ssl" go run main.go db -env dev rollback


Ongoing WIP atm, but for example, can be run with:

$  go test -timeout 30s -run ^TestDeleteUser$


Now you can run the web server with go run main.go runserver.

This will default to running in dev and without debug output from queries.

However, there are two flags:

  • env (dev, test or prod, defaults to dev)
  • dbdebug (true or false, defaults to false)

So e.g. go run main.go runserver -env test -dbdebug true will run the server on the test DB (defined in the config) with db query debug output on.

The PSN connection strings for dev and test are in conf.local.yaml, but for prod this is built from environement variables:

  • POSTGRES_USER (DB username)
  • POSTGRES_PASS (DB password)
  • POSTGRES_HOST (DB host, defaulted
  • POSTGRES_PORT (DB port, defaulted 5432)
  • POSTGRES_SSL (enable or defaulted disable)


Build a container with docker build -t resonateuserapi .

(to avoid cache, use --no-cache option)

Run container with docker run -p 11000:11000 --network=host -tid resonateuserapi

Check status with docker container ls and docker logs <image>

(use sudo as required)

Working with a reverse-proxy (like nginx)

You need to register a certificate in a pair of files.

This prefix of this file is held in the config file as cert_name, default value uaclient

The server will then look for two files, suffix’s “.pem” and “.key” in the directory provided by the environment variable UACERT_DIR

In your reverse proxy you will need to refer to these too in order to be able to proxy the service securely.


Interfaces are designed in proto/ directory. See tutorials and guides on writing protofiles.

Once that is done, regenerate the files using make generate. This will mean you’ll need to implement any functions in server/, or else the build will fail since your struct won’t be implementing the interface defined by the generated file in proto/example.pb.go.


View Github