A goland API that implements a challenge/response mechanism in order to issue JWTs using Ethereum identities. It also (optionally) supports ETH to ENS resolution for users that have registered an ENS name.
$ go get github.com/deiu/eth-authThe server needs the following ENV variables to be set before running:
INFURA_API_URL- [optional] the Infura API URL for ENS resolutionINFURA_API_KEY- [optional] the Infura API key for ENS resolutionORIGINS- list of allowed Origins separated by space (i.e. your client app URL)ETH_PRIVKEY- a private Ethereum key that is used to sign the JWTs (in hexa)LOGGING- whether to log requests to stdout
Example of how to start the server:
$ export INFURA_API_URL="https://rinkeby.infura.io/v3/"
$ export INFURA_API_KEY="2702729979....de7a92e689bfff"
$ export ORIGINS="http://localhost:8888 https://example.org"
$ export ETH_PRIVKEY="your-exported-eth-key-in-hexa"
$ export LOGGING="true"
$ go run server.goImportant! The Infura API URL should match the network used by the client
app. In the example above, it is set to Rinkeby, which means that the client
app should make sure to tell users to set their MetaMask (or similar providers)
current network to Rinkeby as well.
Basically, the way the API works is that a client will send a GET request to
/login/{ethAddress} in order to obtain a unique challenge from the server
that will then be presented to the user in order to be signed with the user's
Ethereum key.
Replace http://api.example.org with your own domain.
Request:
curl 'http://api.example.org/login/0x91ff16a5ffb07e2f58600afc6ff9c1c32ded1f81'Response:
{
address: "0x91ff16a5ffb07e2f58600afc6ff9c1c32ded1f81",
challenge: "To prove your identity, please sign this one-time nonce: JiqPLBbLBdCfWZoS"
}Next, the client must send a POST request to /login/{ethAddress}, containing the
signed challenge. The API will then validate the user's signature and issue the JWT
if the signature is good, together with the token's expiration time.
Request:
curl 'http://api.example.org/login/0x91ff16a5ffb07e2f58600afc6ff9c1c32ded1f81' \
-X POST \
-H 'Content-Type: application/json' \
--data-binary '{"signature": "0x5114fb7...33f5c031c"}'Response:
{
expires: "2020-11-06T15:06:38.602022706Z",
token: "eyJleHAiOjE....fyHd7kPlg",
user: "0x91ff16a5ffb07e2f58600afc6ff9c1c32ded1f81"
}Note: if you have registered an ENS name for your Ethereum address, the user
attribute will return the ENS name instead of a plain Ethereum address.
Clients can obtain a new token as they get closer to the expiration time,
by sending a GET request to /refresh using the (still valid) JWT as a Bearer
token within an Authorization header. The response is similar to the one above,
containing a new expiration date and token:
Request:
curl 'http://api.example.org/refresh' \
-H 'Authorization: Bearer eyJleHAiOjE....fyHd7kPlg'Response:
{
expires: "2020-11-06T15:06:38.602022706Z",
token: "eyJleHAiOjE2MD....fY1qv8Oxjw",
user: "0x91ff16a5ffb07e2f58600afc6ff9c1c32ded1f81"
}If you want to see a full example check out the test-client directory from this
repo for a small client app in JavaScript, which uses Metamask as the Ethereum provider.