Skip to content

Authentication

Andy Dunstall edited this page Jul 16, 2024 · 4 revisions

Piko uses a JSON Web Token (JWT) provided by your application to authenticate connecting clients. To enable authentication, configure the Piko server with a secret key or public key to verify the client JWT. The JWT may also include Piko specific claims the server will verify, such as what endpoints the client is permitted to connect to or listen on.

Each server port has independent configuration, such as you may authenticate upstream listeners but not clients connecting to the proxy port.

Piko supports HMAC, RSA, and ECDSA JWT algorithms, specifically HS256, HS384, HS512, RSA256, RSA384, RSA512, EC256, EC384, and EC512.

Each port has configuration:

auth:
  # Secret key to authenticate HMAC endpoint connection JWTs.
  hmac_secret_key: ""

  # Public key to authenticate RSA endpoint connection JWTs.
  rsa_public_key: ""

  # Public key to authenticate ECDSA endpoint connection JWTs.
  ecdsa_public_key: ""

  # Audience of endpoint connection JWT token to verify.
  #
  # If given the JWT 'aud' claim must match the given audience. Otherwise it
  # is ignored.
  audience: ""

  # Issuer of endpoint connection JWT token to verify.
  #
  # If given the JWT 'iss' claim must match the given issuer. Otherwise it
  # is ignored.
  issuer: ""

Such as to configure the HMAC secret key for the 'upstream' port, configure upstream.auth.hmac-secret-key.

If any of the secret key or public key options are configured, then clients must include a valid JWT that can be verified by one of those keys.

Piko will verify the exp (expiry) and iat (issued at) claims if included in the JWT.

You can also optionally configure the audience and issuer options, which Piko will use to verify the aud and iss JWT claims respectively. If empty Piko won't verify the claims.

Piko also supports JWTs with a configured set of endpoint IDs that the client can access using claim piko.endpoints. When configured on the 'proxy' port, this is the list of endpoints the client can connect to, or when configured on the 'upstream' port it is the endpoints the upstream can listen on. Such as if the JWT includes claim "piko": {"endpoints": ["endpoint-123"]}, it will be permitted to access endpoint ID endpoint-123 only. If the piko.endpoints claim is not included in the JWT, the client can access any endpoint.

Example

This example shows you how to create a simple HS256 JWT using Python and use it to configure Piko clients and upstreams.

Token

First create a HS256 JWT token in Python using a HMAC secret key my-secret:

import jwt

token = jwt.encode({}, "my-secret")
print(token)  # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiJ9.cYo84rqiyvYovXGPGxY7a4qWLa5HA857Nb2uMrkVcHs

As described above, you can also include Piko specific claims in the JWT payload. Such as to restrict the client to endpoint my-endpoint only, use:

token = jwt.encode({"piko": {"endpoints": ["my-endpoint"]}}, "my-secret")
print(token)  # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwaWtvIjp7ImVuZHBvaW50cyI6WyJteS1lbmRwb2ludCJdfX0.I7Vkc2w0-CuEUz-ePRBEFx_-9aCAOH6BN146BZBIxGw

Server

Next start the Piko server and configure it to verify the client JWT using the HMAC secret. This example enables authentication on both the 'proxy' port and 'upstream port':

$ piko server --proxy.auth.hmac-secret-key my-secret --upstream.auth.hmac-secret-key my-secret

You can also configure the server using YAML configuration, such as:

# server.yaml

proxy:
  auth:
    hmac_secret_key: my-secret
upstream:
  auth:
    hmac_secret_key: my-secret

Then run the server with:

$ piko server --config.path ./server.yaml

HTTP

HTTP clients connecting to the proxy port must then include an Authorization: Bearer <token>, replacing the token with one of the JWT's created above, such as:

$ curl http://localhost:8000 \
    -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwaWtvIjp7ImVuZHBvaW50cyI6WyJteS1lbmRwb2ludCJdfX0.I7Vkc2w0-CuEUz-ePRBEFx_-9aCAOH6BN146BZBIxGw" \
    -H "x-piko-endpoint: my-endpoint"

Agent

When adding upstream listeners using piko agent, to authenticate the agent you must configure --connect.token to authenticate the agent with the server. Such as:

$ piko agent http my-endpoint 3000 --connect.token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwaWtvIjp7ImVuZHBvaW50cyI6WyJteS1lbmRwb2ludCJdfX0.I7Vkc2w0-CuEUz-ePRBEFx_-9aCAOH6BN146BZBIxGw

Forward

When connecting to Piko using piko forward, to authenticate the forward client you must configure --connect.token. Such as:

$ piko forward tcp 6000 my-endpoint --connect.token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwaWtvIjp7ImVuZHBvaW50cyI6WyJteS1lbmRwb2ludCJdfX0.I7Vkc2w0-CuEUz-ePRBEFx_-9aCAOH6BN146BZBIxGw

Note when using piko forward you don't have to authenticate the client that connects to Piko via piko forward.