Module: Ask::MCP::Auth::ClientIdMetadataDocument
- Defined in:
- lib/ask/mcp/auth/client_id_metadata_document.rb
Overview
OAuth Client ID Metadata Documents (2026-07-28, SEP-991) — the recommended client registration mechanism, replacing the deprecated Dynamic Client Registration Protocol (RFC 7591).
A client_id is an HTTPS URL pointing to a JSON document describing the client; the authorization server fetches and validates it on demand. Because the document is self-hosted, URL-based client IDs are portable across authorization servers — no re-registration needed when the server changes.
Constant Summary collapse
- REQUIRED_FIELDS =
Fields every metadata document MUST include.
%w[client_id client_name redirect_uris].freeze
- APPLICATION_TYPES =
OIDC application types (native = desktop/mobile/CLI/localhost web).
%w[native web].freeze
Class Method Summary collapse
-
.build(client_id:, client_name:, redirect_uris:, application_type: "native", **extra) ⇒ Object
Build a metadata document hash.
-
.invalid_reason(document, document_url: nil) ⇒ Object
Validate a fetched document.
-
.valid_client_id_url?(client_id) ⇒ Boolean
Whether the client_id has the required URL form: https scheme with a path component (e.g. https://example.com/client.json).
Class Method Details
.build(client_id:, client_name:, redirect_uris:, application_type: "native", **extra) ⇒ Object
Build a metadata document hash. client_id must be an https URL
with a path component; redirect_uris must be a non-empty array.
Extra keyword args are included verbatim (string keys).
28 29 30 31 32 33 34 35 |
# File 'lib/ask/mcp/auth/client_id_metadata_document.rb', line 28 def build(client_id:, client_name:, redirect_uris:, application_type: "native", **extra) { "client_id" => client_id, "client_name" => client_name, "redirect_uris" => redirect_uris, "application_type" => application_type }.merge(extra.transform_keys(&:to_s)) end |
.invalid_reason(document, document_url: nil) ⇒ Object
Validate a fetched document. Returns nil when valid, or a reason
string. When document_url is given, the document's client_id MUST
match it exactly.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ask/mcp/auth/client_id_metadata_document.rb', line 49 def invalid_reason(document, document_url: nil) return "metadata document must be a JSON object" unless document.is_a?(Hash) missing = REQUIRED_FIELDS.reject { |f| document[f] || document[f.to_sym] } return "missing required fields: #{missing.join(', ')}" unless missing.empty? client_id = (document["client_id"] || document[:client_id]).to_s if document_url && client_id != document_url return "client_id #{client_id.inspect} does not match document URL #{document_url.inspect}" end return "client_id must be an https URL with a path" unless valid_client_id_url?(client_id) redirect_uris = document["redirect_uris"] || document[:redirect_uris] return "redirect_uris must be a non-empty array" unless redirect_uris.is_a?(Array) && !redirect_uris.empty? app_type = document["application_type"] || document[:application_type] if app_type && !APPLICATION_TYPES.include?(app_type.to_s) return "invalid application_type #{app_type.inspect}" end nil end |
.valid_client_id_url?(client_id) ⇒ Boolean
Whether the client_id has the required URL form: https scheme with a path component (e.g. https://example.com/client.json).
39 40 41 42 43 44 |
# File 'lib/ask/mcp/auth/client_id_metadata_document.rb', line 39 def valid_client_id_url?(client_id) uri = URI.parse(client_id.to_s) uri.scheme == "https" && !uri.path.to_s.empty? && uri.path != "/" rescue URI::InvalidURIError false end |