vestibule_indieauth/discovery
IndieAuth endpoint discovery.
vestibule_indieauth/discovery
IndieAuth endpoint discovery.
Implements the discovery algorithm from IndieAuth spec Section 4.1:
- Fetch the user’s profile URL
- Look for
rel="indieauth-metadata"— if found, fetch metadata JSON - Fall back to
rel="authorization_endpoint"andrel="token_endpoint" - Check HTTP
Linkheaders first, then HTML<link>tags
Types
DiscoveredEndpoints
Endpoints discovered from a user’s IndieAuth server.
pub type DiscoveredEndpoints { DiscoveredEndpoints( authorization_endpoint: String, token_endpoint: String, issuer: option.Option(String), userinfo_endpoint: option.Option(String) )}ProfileDiscovery
Result of parsing a profile-page discovery response.
A profile can either contain the authorization and token endpoint links directly, or point to a metadata document that requires one more request.
pub type ProfileDiscovery { EndpointsDiscovered(DiscoveredEndpoints) MetadataRequired(url: String)}Functions
build_metadata_request
Build an IndieAuth metadata request without sending it.
The returned request is opaque and must be sent with
provider_support.send_public.
pub fn build_metadata_request(String) -> Result(provider_support.SecureRequest, error.AuthError(a))build_profile_request
Build the request used to discover endpoints from a profile page.
The profile URL must be public HTTPS. The returned request is opaque and
can only be sent with provider_support.send_public, so DNS validation and
address pinning cannot be accidentally bypassed.
pub fn build_profile_request(String) -> Result(provider_support.SecureRequest, error.AuthError(a))discover_endpoints
Discover IndieAuth endpoints from a user’s profile URL.
Fetches the URL and discovers endpoints using the three-tier fallback:
- IndieAuth server metadata (
rel="indieauth-metadata") - Direct link relations (
rel="authorization_endpoint",rel="token_endpoint") - HTTP
Linkheaders take precedence over HTML<link>tags
pub fn discover_endpoints(String) -> Result(DiscoveredEndpoints, error.AuthError(a))find_html_link_relation
Find an HTML <link> element with the given rel attribute.
Uses presentable_soup for robust HTML parsing. Exported for testing.
pub fn find_html_link_relation( String, String) -> option.Option(String)find_link_header_relation
Parse HTTP Link headers to find a URL with the given rel value.
Handles the format: <URL>; rel="value" or <URL>; rel=value
Exported for testing.
pub fn find_link_header_relation( List(#(String, String)), String) -> option.Option(String)parse_metadata
Parse IndieAuth server metadata JSON. Exported for testing.
pub fn parse_metadata(String) -> Result(DiscoveredEndpoints, error.AuthError(a))parse_metadata_response
Parse an IndieAuth metadata HTTP response without performing I/O.
pub fn parse_metadata_response( String, response.Response(String)) -> Result(DiscoveredEndpoints, error.AuthError(a))parse_profile_response
Parse a profile-page discovery HTTP response without performing I/O.
pub fn parse_profile_response( String, response.Response(String)) -> Result(ProfileDiscovery, error.AuthError(a))validate_endpoints
Require every discovered endpoint to be a structurally safe HTTPS URL.
Discovered endpoints are chosen by whoever controls the profile URL, so
without this check a login attempt could point the server’s token or
userinfo requests at loopback, private, or cloud-metadata addresses
(SSRF). Literal non-public addresses are rejected here. Immediately before
each server-side request, provider_support.send_public additionally
resolves every DNS answer, rejects mixed/non-public results, and pins the
validated address to the connection.
pub fn validate_endpoints(DiscoveredEndpoints) -> Result(DiscoveredEndpoints, error.AuthError(a))