FdsnPlugs

View Source

coverage report hex.pm hexdocs.pm

Collection of plugs related to FDSN webservices.

Installation

If available in Hex, the package can be installed by adding fdsn_plugs to your list of dependencies in mix.exs:

def deps do
  [
    {:fdsn_plugs, "~> 0.9.0"}
  ]
end

Usage

This module provides two supersets of plugs: FdsnDataselectPlugs and FdsnAvailabilityPlugs to implement dataselect and availability web services.

Phoenix

Add the plug collection to your pipeline:

pipeline :fdsn do
    plug :accepts, ["json", "text", "mseed"]
    plug FdsnDataselectPlugs
end

JWT authentication

FdsnPlugs.JWTAuthentication is included in both pipeline supersets. It authenticates requests via JWT bearer tokens, supporting multiple token authorities.

1. Start one FdsnPlugs.JwkStrategy per authority in your supervision tree

Each strategy fetches and caches JWKS signing keys from the given URL.

children = [
  {FdsnPlugs.JwkStrategy,
   name: :eida,
   jwks_url: "https://geofon.gfz.de/eas2/jwk",
   time_interval: 600_000,
   first_fetch_sync: true},
  {FdsnPlugs.JwkStrategy,
   name: :other_authority,
   jwks_url: "https://auth.example.com/jwks",
   first_fetch_sync: true}
]

first_fetch_sync must be set to true.

Alternative: configuration via environment variable

FdsnPlugs.JwkConfig.child_specs/0 reads a JWT_AUTHORITIES JSON array from the environment and returns the corresponding child specs. Use it to keep the supervision tree declarative:

children =
  FdsnPlugs.JwkConfig.child_specs() ++ [
    # your other children…
  ]

The env var format is a JSON array of objects, each with a "name" and "jwks_url":

export JWT_AUTHORITIES='[
  {"name":"eida","jwks_url":"https://geofon.gfz.de/eas2/jwk"},
  {"name":"other","jwks_url":"https://auth.example.com/jwks","time_interval":3600000}
]'

If the env var is unset, empty, or malformed, child_specs/0 returns [] and no strategies are started.

2. Configure which authorities the plug should try

Via application config:

config :fdsn_plugs, :jwt_authorities, [:eida, :other_authority]

Via environment variable:

config :fdsn_plugs, :jwt_authorities, FdsnPlugs.JwkConfig.authority_names()

Or inline in a custom pipeline:

plug FdsnPlugs.JWTAuthentication, authorities: [:eida, :other_authority]

How it works

  1. If conn.assigns.user is already set (e.g. HTTP Digest auth from your application), the plug passes through.
  2. If no Authorization header is present, the plug passes through.
  3. On a Bearer <token> header, each authority is tried in order.
  4. On success, all token claims are stored in conn.assigns.jwt_claims and the email claim is stored in conn.assigns.user.
  5. If no authority validates the token, a 401 response is returned with a WWW-Authenticate header explaining the reason.

Testing with curl

The token must be the raw JWT (access_token value), not the full OAuth2 JSON response. Extract it with jq:

ACCESS_TOKEN=$(jq -r '.access_token' token.json)
curl --oauth2-bearer "$ACCESS_TOKEN" "https://your-server/fdsnws/dataselect/1/query?net=FR&sta=RUSF"

Or test directly against the EIDA JWKS without a server:

ACCESS_TOKEN=$(jq -r .access_token ~/Téléchargements/eidajwt.json) mix run bin/verify_jwt.exs

Logging

The library uses Elixir's Logger for its log messages.

Changing the log level during tests

Test log level is configured in test/test_helper.exs via Logger.configure(level: :warning). The default is :warning; valid values are :debug, :info, :warning, and :error.

# test/test_helper.exs
Logger.configure(level: :info)