Module: Hitch::MCP::Internal::BearerChallenge

Defined in:
app/models/hitch/mcp/internal/bearer_challenge.rb

Overview

Bearer token extraction and the WWW-Authenticate challenges the endpoint issues (RFC 6750 ยง3, RFC 9728 protected-resource metadata).

Constant Summary collapse

MAX_BEARER_TOKEN_BYTES =
512

Class Method Summary collapse

Class Method Details

.challengeObject

A generic 401 starts the least-privilege authorization flow with the host's base/default scope. Protected-resource metadata still advertises the complete supported set, and a known available tool names its complete static requirement in a later 403 step-up.



29
30
31
32
# File 'app/models/hitch/mcp/internal/bearer_challenge.rb', line 29

def challenge
  scope = Hitch.configuration.supported_scopes.first
  %(Bearer resource_metadata="#{}", scope="#{scope}")
end

.insufficient_scope(required_scopes) ⇒ Object



34
35
36
37
38
# File 'app/models/hitch/mcp/internal/bearer_challenge.rb', line 34

def insufficient_scope(required_scopes)
  "Bearer error=\"insufficient_scope\", " \
    "scope=\"#{required_scopes.join(' ')}\", " \
    "resource_metadata=\"#{}\""
end

.resource_metadata_urlObject

Derived from the canonical resource_uri, not handed in: the issuer inside a challenge must be the same bytes discovery advertises, and the one derivation is what guarantees it (INV-MCP-024).



43
44
45
46
47
# File 'app/models/hitch/mcp/internal/bearer_challenge.rb', line 43

def 
  Hitch::ResourceUri.(
    URI.parse(Hitch.configuration.resource_uri.to_s)
  )
end

.token(authorization) ⇒ Object



15
16
17
18
19
20
21
22
23
# File 'app/models/hitch/mcp/internal/bearer_challenge.rb', line 15

def token(authorization)
  authorization = authorization.to_s
  return if authorization.bytesize > MAX_BEARER_TOKEN_BYTES + 7
  return unless authorization.valid_encoding?
  return if authorization.match?(/[\u0000-\u001F\u007F-\u009F]/)

  match = authorization.match(/\ABearer ([A-Za-z0-9_-]{1,#{MAX_BEARER_TOKEN_BYTES}})\z/i)
  match && match[1]
end