package

github.com/tekanic/pika-auth

0.1.0 / published May 5, 2026 / repository

Authentication strategies for Pika — Bearer token, API key, HTTP Basic

pika-auth

Authentication strategies for Pika — plug-in Bearer token, API key, and HTTP Basic auth with class-level or per-resource control.

Installation

Add to your shard.yml:

dependencies:
  pika-auth:
    github: tekanic/pika-auth
    version: "~> 0.1"

Then run shards install.

Usage

require "pika-auth"

Include the module

class MyAPI < Pika::API
  include Pika::Auth
  # ...
end

include Pika::Auth installs a before hook that runs Pika::Auth.check! on every request. By itself it does nothing — you need to define at least one strategy.


Class-level auth

Use the auth macro to set a default strategy for the entire API class.

class MyAPI < Pika::API
  include Pika::Auth

  auth :bearer do |token|
    token == ENV["API_TOKEN"]
  end

  resource :users do
    get { User.all.to_json }
  end
end

Every request to every route in MyAPI must now supply a valid Bearer token.


Per-resource overrides

public_resource — no auth required

class MyAPI < Pika::API
  include Pika::Auth

  auth :bearer do |token|
    Token.valid?(token)
  end

  public_resource :health do
    get { {status: "ok"}.to_json }
  end

  resource :users do
    get { User.all.to_json }  # bearer required
  end
end

GET /health is completely open; all other routes still require a Bearer token.

resource_auth — different strategy per resource

class MyAPI < Pika::API
  include Pika::Auth

  auth :bearer do |token|
    UserToken.valid?(token)
  end

  resource_auth :webhooks, :api_key do |key|
    key == ENV["WEBHOOK_SECRET"]
  end do
    post { handle_webhook }
  end
end

POST /webhooks is authenticated with the api_key strategy; everything else uses the bearer default.


Strategies

BearerToken

Reads the token from Authorization: Bearer <token>.

auth :bearer do |token|
  Token.find_by(value: token) != nil
end

ApiKey

Reads the key from a header (default X-API-Key) and/or a query parameter. The header is checked first.

auth :api_key do |key|
  key == ENV["API_KEY"]
end

Custom header and/or query param (register manually):

Pika::Auth.register(
  :api_key,
  Pika::Auth::Strategies::ApiKey.new(
    validator:   ->(k : String) { k == ENV["API_KEY"] },
    header:      "X-My-Key",
    query_param: "key"
  )
)

Basic

Reads credentials from Authorization: Basic <base64(username:password)>.

auth :basic do |username, password|
  username == "admin" && password == ENV["ADMIN_PASSWORD"]
end

Error handling

All strategies raise Pika::UnauthorizedError on failure. Pika converts this to a 401 Unauthorized response with a JSON body by default:

{"error": "Unauthorized"}

Multiple strategies in one API

You can register several named strategies and mix them across resources:

class MyAPI < Pika::API
  include Pika::Auth

  auth :bearer do |token|
    UserToken.valid?(token)
  end

  resource_auth :internal, :api_key do |key|
    key == ENV["INTERNAL_KEY"]
  end do
    get { InternalData.all.to_json }
  end

  public_resource :health do
    get { "ok" }
  end

  resource :users do
    get { User.all.to_json }  # bearer (class default)
  end
end
PathStrategy
GET /healthnone (public)
GET /usersbearer (class default)
GET /internalapi_key (per-resource)

License

MIT

API