Class: Steppe::Auth::Bearer

Inherits:
Object
  • Object
show all
Includes:
Responses
Defined in:
lib/steppe/auth/bearer.rb

Overview

HTTP Bearer token authentication security scheme. Validates Bearer tokens from the Authorization header and checks permissions against a token store.

Examples:

store = Steppe::Auth::HashTokenStore.new({
  'token123' => ['read:users', 'write:users']
})
bearer = Steppe::Auth::Bearer.new('my_auth', store: store)

# In a service definition:
api.security_scheme bearer

# Or use the shortcut
api.bearer_auth 'my_auth', store: { 'token123' => ['read:users'] }

# Then in an endpoint in the service:
e.security 'my_auth', ['read:users']

Defined Under Namespace

Classes: HashTokenStore

Constant Summary collapse

TokenStoreInterface =

Interface for custom token store implementations. Required methods:

  • get(token): Returns an access token object or nil

Types::Interface[:get]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, store:, scheme: 'bearer', format: nil, header: HTTP_AUTHORIZATION) ⇒ Bearer

Initialize a new Bearer authentication scheme.

Parameters:

  • name (String)

    The security scheme name (used in OpenAPI)

  • store (TokenStoreInterface)

    Token store for validating access tokens

  • scheme (String) (defaults to: 'bearer')

    The authentication scheme (default: ‘bearer’)

  • format (String, nil) (defaults to: nil)

    Optional bearer format hint (e.g., ‘JWT’)

  • header (String) (defaults to: HTTP_AUTHORIZATION)

    The HTTP header to check (default: HTTP_AUTHORIZATION)



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/steppe/auth/bearer.rb', line 78

def initialize(name, store:, scheme: 'bearer', format: nil, header: HTTP_AUTHORIZATION)
  @name = name
  @store = case store
  when HashTokenStore::Interface
    HashTokenStore.new(store)
  when TokenStoreInterface
    store
  else
    raise ArgumentError, "expected a TokenStore interface #{TokenStoreInterface}, but got #{store.inspect}"
  end

  @format = format.to_s
  @scheme = scheme.to_s
  @header = header
  # We mark the key as optional
  # because we don't validate presence of the header and return a 422.
  # (even though that'll most likely result in a 401 response after running #handle)
  @header_schema = Types::Hash["#{@header}?" => String]
  @matcher = %r{\A\s*#{Regexp.escape(@scheme)}\s+(.+?)\s*\z}i
end

Instance Attribute Details

#formatObject (readonly)

Returns the value of attribute format.



69
70
71
# File 'lib/steppe/auth/bearer.rb', line 69

def format
  @format
end

#header_schemaObject (readonly)

Returns the value of attribute header_schema.



69
70
71
# File 'lib/steppe/auth/bearer.rb', line 69

def header_schema
  @header_schema
end

#nameObject (readonly)

Returns the value of attribute name.



69
70
71
# File 'lib/steppe/auth/bearer.rb', line 69

def name
  @name
end

#schemeObject (readonly)

Returns the value of attribute scheme.



69
70
71
# File 'lib/steppe/auth/bearer.rb', line 69

def scheme
  @scheme
end

Instance Method Details

#handle(conn, required_scopes) ⇒ Steppe::Result::Continue, Steppe::Result::Halt

Handle authentication and authorization for a connection. Validates the Bearer token from the Authorization header and checks if it has required scopes.

Parameters:

  • conn (Steppe::Result)

    The connection/result object

  • required_scopes (Array<String>)

    The scopes required for this endpoint

Returns:



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/steppe/auth/bearer.rb', line 116

def handle(conn, required_scopes)
  header_value = conn.request.get_header(@header).to_s.strip
  return unauthorized(conn) if header_value.empty?

  token = header_value[@matcher, 1]
  return unauthorized(conn) if token.nil?

  access_token = @store.get(token)
  return forbidden(conn) unless access_token&.allows?(required_scopes)

  conn
end

#to_openapiHash

Convert this security scheme to OpenAPI 3.0 format.

Returns:

  • (Hash)

    OpenAPI security scheme object



102
103
104
105
106
107
108
# File 'lib/steppe/auth/bearer.rb', line 102

def to_openapi
  {
    'type' => 'http',
    'scheme' => scheme,
    'bearerFormat' => format
  }
end