Documentation ¶
Overview ¶
This package provides a set of tools to help you implement an IndieAuth client or server, according to the specification.
Index ¶
- Constants
- Variables
- func CanonicalizeURL(urlStr string) string
- func IsValidClientIdentifier(identifier string) error
- func IsValidCodeChallengeMethod(ccm string) bool
- func IsValidProfileURL(profile string) error
- func ValidateCodeChallenge(ccm, cc, ver string) bool
- type ApplicationMetadata
- type AuthInfo
- type AuthenticationRequest
- type Client
- func (c *Client) Authenticate(ctx context.Context, profile, scope string) (*AuthInfo, string, error)
- func (c *Client) DiscoverLinkEndpoint(ctx context.Context, urlStr, rel string) (string, error)
- func (c *Client) DiscoverMetadata(ctx context.Context, urlStr string) (*Metadata, error)
- func (c *Client) FetchProfile(ctx context.Context, i *AuthInfo, code string) (*Profile, error)
- func (c *Client) GetOAuth2(m *Metadata) *oauth2.Config
- func (c *Client) GetToken(ctx context.Context, i *AuthInfo, code string) (*oauth2.Token, *oauth2.Config, error)
- func (c *Client) ValidateCallback(i *AuthInfo, r *http.Request) (string, error)
- type Metadata
- type Profile
- type Server
Examples ¶
Constants ¶
const ( AuthorizationEndpointRel string = "authorization_endpoint" TokenEndpointRel string = "token_endpoint" IndieAuthMetadataRel string = "indieauth-metadata" )
Variables ¶
var ( ErrCodeNotFound error = errors.New("code not found") ErrStateNotFound error = errors.New("state not found") ErrInvalidState error = errors.New("state does not match") ErrInvalidIssuer error = errors.New("issuer does not match") )
var ( ErrInvalidRedirectURI error = errors.New("redirect_uri is invalid") ErrInvalidCodeChallengeMethod error = errors.New("invalid code challenge method") ErrInvalidGrantType error = errors.New("grant_type must be authorization_code") ErrNoMatchClientID error = errors.New("client_id differs") ErrNoMatchRedirectURI error = errors.New("redirect_uri differs") ErrPKCERequired error = errors.New("pkce is required, not provided") ErrCodeChallengeFailed error = errors.New("code challenge failed") ErrInvalidResponseType error = errors.New("response_type must be code") ErrWrongCodeVerifierLength error = errors.New("code_verifier length must be between 43 and 128 characters long") // RFC 7636, section 4.1 ErrWrongCodeChallengeLength error = errors.New("code_challenge length must be between 43 and 128 characters long") // RFC 7636, section 4.2 )
var ( ErrInvalidProfileURL error = errors.New("invalid profile URL") ErrInvalidClientIdentifier error = errors.New("invalid client identifier") ErrInvalidScheme error = errors.New("scheme must be either http or https") ErrEmptyPath error = errors.New("path must not be empty") ErrInvalidPath error = errors.New("path cannot contain single or double dots") ErrInvalidFragment error = errors.New("fragment must be empty") ErrUserIsSet error = errors.New("user and or password must not be set") ErrPortIsSet error = errors.New("port must not be set") ErrIsIP error = errors.New("profile cannot be ip address") ErrIsNonLoopback error = errors.New("client id cannot be non-loopback ip") )
var CodeChallengeMethods = []string{
"plain", "S256",
}
CodeChallengeMethods are the code challenge methods that are supported by this package.
var ErrNoApplicationMetadata error = errors.New("application metadata (h-app, h-x-app) not found")
ErrNoApplicationMetadata is returned when no `h-app` or `h-x-app` Microformat has been found at a given URL.
var ErrNoEndpointFound = fmt.Errorf("no endpoint found")
ErrNoEndpointFound is returned when no endpoint can be found for a certain target URL.
Functions ¶
func CanonicalizeURL ¶
CanonicalizeURL checks if a URL has a path, and appends a path "/"" if it has no path.
Example ¶
fmt.Println(CanonicalizeURL("example.com"))
Output: https://example.com/
func IsValidClientIdentifier ¶
IsValidClientIdentifier validates a client identifier according to the specification.
func IsValidCodeChallengeMethod ¶
IsValidCodeChallengeMethod returns whether the provided code challenge method is valid or not.
func IsValidProfileURL ¶
IsValidProfileURL validates the profile URL according to the specification.
func ValidateCodeChallenge ¶
ValidateCodeChallenge validates a code challenge against its code verifier. Right now, we support "plain" and "S256" code challenge methods.
The caller is responsible for handling cases where the length of the code challenge or code verifier fall outside the range permitted by RFC 7636.
Types ¶
type ApplicationMetadata ¶ added in v0.3.0
type AuthenticationRequest ¶
type Client ¶
Client is an IndieAuth client. As a client, you want to authenticate other users to log into your website. An example of how to use the client library can be found in the examples/client/ directory.
func NewClient ¶
NewClient creates a new Client from the provided clientID and redirectURL. If no httpClient is given, http.DefaultClient will be used.
func (*Client) Authenticate ¶
func (c *Client) Authenticate(ctx context.Context, profile, scope string) (*AuthInfo, string, error)
Authenticate takes a profile URL and the desired scope, discovers the required endpoints, generates a random state and code challenge (using method SHA256), and builds the authorization URL. It returns the authorization info, redirect URI and an error.
The returned AuthInfo should be stored by the caller of this function in such a way that it can be retrieved to validate the callback.
func (*Client) DiscoverLinkEndpoint ¶
DiscoverLinkEndpoint discovers as given endpoint identified by rel.
func (*Client) DiscoverMetadata ¶
DiscoverMetadata discovers the IndieAuth metadata of the provided URL, such as the authorization and token endpoints. This code is partially based on webmention.DiscoverEndpoint.
func (*Client) FetchProfile ¶
FetchProfile fetches the user Profile, exchanging the authentication code from their authentication endpoint, as per specification. Please note that this action consumes the code.
func (*Client) GetOAuth2 ¶
GetOAuth2 returns an oauth2.Config based on the given endpoints. This can be used to get an http.Client. See the documentation of oauth2 for more details.
func (*Client) GetToken ¶
func (c *Client) GetToken(ctx context.Context, i *AuthInfo, code string) (*oauth2.Token, *oauth2.Config, error)
GetToken exchanges the code for an oauth2.Token based on the provided information. It returns the token and an oauth2.Config object which can be used to create an http client that uses the token on future requests.
Note that token.Raw may contain other information returned by the server, such as "Me", "Profile" and "Scope".
token, oauth2, err := client.GetToken(authData, code) if err != nil { // Do something } httpClient := oauth2.Client(context.Background(), token)
You can now use httpClient to make requests to, for example, a Micropub endpoint. They are authenticated with token. See https://pkg.go.dev/golang.org/x/oauth2 for more details.
type Metadata ¶
type Metadata struct { Issuer string `json:"issuer"` AuthorizationEndpoint string `json:"authorization_endpoint"` TokenEndpoint string `json:"token_endpoint"` IntrospectionEndpoint string `json:"introspection_endpoint"` IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported"` RevocationEndpoint string `json:"revocation_endpoint"` RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported"` ScopesSupported []string `json:"scopes_supported"` ResponseTypesSupported []string `json:"response_types_supported"` GrantTypesSupported []string `json:"grant_types_supported"` ServiceDocumentation []string `json:"service_documentation"` CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` AuthorizationResponseIssParameterSupported bool `json:"authorization_response_iss_parameter_supported"` UserInfoEndpoint string `json:"userinfo_endpoint"` }
type Profile ¶
type Profile struct { Me string `json:"me"` Profile struct { Name string `json:"name"` URL string `json:"url"` Photo string `json:"photo"` Email string `json:"email"` } `json:"profile"` }
func ProfileFromToken ¶
ProfileFromToken retrieves the extra information from the token and creates a profile based on it. Note that the profile may be nil in case no information can be retrieved.
type Server ¶
func NewServer ¶
NewServer creates a new Server that from the given options. If no httpClient is given, http.DefaultClient will be used.
func (*Server) DiscoverApplicationMetadata ¶ added in v0.3.0
func (s *Server) DiscoverApplicationMetadata(ctx context.Context, clientID string) (*ApplicationMetadata, error)
DiscoverApplicationMetadata fetches metadata for the application at the provided URL. This metadata is given by the `h-app` or `h-x-app` Microformat. This information can be used by the server, for example, to display relevant information about the application in the authorization page. If no information has been found, an ErrNoApplicationMetadata error will be returned.
Please note that this function only parses the first `h-app` or `h-x-app` Microformat with information that it encounters.
func (*Server) ParseAuthorization ¶
func (s *Server) ParseAuthorization(r *http.Request) (*AuthenticationRequest, error)
ParseAuthorization parses an authorization request and returns all the collected information about the request.
func (*Server) ValidateTokenExchange ¶
func (s *Server) ValidateTokenExchange(authRequest *AuthenticationRequest, r *http.Request) error
ValidateTokenExchange validates the token exchange request according to the provided authentication request and returns an error.
Please note that you need to fetch the authentication code yourself from the request.
_ = r.ParseForm() code := r.Form.Get("code")
The code was provided by you at a previous stage. Thus, you will need to use it to rebuild the AuthenticationRequest data. The AuthenticationRequest does not need to have the scope or state set for this validation.