Noizu.MCP.Auth.ApiKeyVerifier (Noizu MCP v0.1.6)

Copy Markdown View Source

Accepts a raw API key presented as a bearer token.

Headless callers (a cron job, a CI step, a CLI that cannot open a browser) have no way to run the OAuth dance. This verifier lets them present a long-lived key in the same Authorization: Bearer header, so a mount can serve both audiences — pair it with Noizu.MCP.Auth.ChainVerifier.

auth: [
  verifier: {Noizu.MCP.Auth.ChainVerifier, [
    verifiers: [
      {Noizu.MCP.Auth.JWTVerifier, [resource: resource, secret: {MyApp, :secret}]},
      {Noizu.MCP.Auth.ApiKeyVerifier, [
        resource: resource,
        prefix: "mcp_live_",
        validator: {MyApp.MCPKeys, :verify}
      ]}
    ]
  ]}
]

The key store belongs to the host — only it knows the table. :validator is called with the presented key and must answer {:ok, claims} | {:error, reason} | false | nil. It must compare against a hash, not a plaintext column; Noizu.MCP.Auth.Server.Secret provides token_hash/1 and a constant-time equal?/2 for that.

Options

  • :validator (required unless :keys is given) — {module, function}, {module, function, extra_args} (the key is prepended), or a 1-arity fun.
  • :keys — a static [{key, claims}] list, compared in constant time. For tests and single-operator deployments; a real key list belongs in a database, behind :validator.
  • :resource — canonical resource URI of the mount. Stamped onto the claims as aud when the validator did not set one: an API key is bound to a resource by where it was configured, and downstream code that reads aud should see the same shape either way.
  • :prefix — required key prefix. A cheap non-secret shape check that keeps obviously-wrong credentials (an OAuth JWT, say) from reaching the database on every request.
  • :scopes — scopes the resulting claims must carry, checked exactly as Noizu.MCP.Auth.JWTVerifier does.
  • :default_claims — merged under whatever the validator returns (e.g. %{"scope" => "mcp"}).

Failure is always {:error, :invalid_token} — a caller cannot distinguish "no such key" from "revoked key" from "wrong prefix".