indieauth

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 23, 2020 License: MIT Imports: 9 Imported by: 3

Documentation

Overview

Package indieauth authenticates clients using IndieAuth.

This package implements methods for clients to perform the authetication or authorization IndieAuth flows.

Further Reading

Spec: https://www.w3.org/TR/indieauth/

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthenticationConfig

type AuthenticationConfig struct {
	ClientID    *url.URL
	RedirectURI *url.URL
	Client      *http.Client
}

AuthenticationConfig provides the data for a client that wants to authenticate users.

func Authentication

func Authentication(clientID, redirectURI string) (*AuthenticationConfig, error)
Example
package main

import (
	"net/http"

	"hawx.me/code/indieauth"
)

func main() {
	randomString := func() string {
		return "abcde"
	}

	setCookie := func(w http.ResponseWriter, r *http.Request, me string) {
		// more code...
	}

	// obviously don't do this in real code
	sessions := map[string]indieauth.Endpoints{}

	// first we get the configuration for our client
	config, _ := indieauth.Authentication(
		"http://client.example.com/",
		"http://client.example.com/callback")

	// then we can create a handler for redirecting to when we want to sign
	// someone in to our app
	http.HandleFunc("/sign-in", func(w http.ResponseWriter, r *http.Request) {
		state := randomString()

		// get the authorization_endpoint for the user
		endpoints, _ := indieauth.FindEndpoints(r.FormValue("me"))
		sessions[state] = endpoints

		// construct the URL where the user can authenticate (or not) our app
		redirectURL := config.RedirectURL(endpoints, r.FormValue("me"), "some-random-state")
		http.Redirect(w, r, redirectURL, http.StatusFound)
	})

	http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
		state := r.FormValue("state")

		endpoints, ok := sessions[state]
		if !ok {
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}

		// finally we swap the code we got for the authenticated profile URL
		me, err := config.Exchange(endpoints, r.FormValue("code"))
		if err != nil {
			http.Redirect(w, r, "/?error", http.StatusFound)
			return
		}

		// and can set it to a cookie, or whatever is needed
		setCookie(w, r, me)
		http.Redirect(w, r, "/", http.StatusFound)
	})
}
Output:

func (*AuthenticationConfig) Exchange

func (c *AuthenticationConfig) Exchange(endpoints Endpoints, code string) (me string, err error)

Exchange converts an authentication code into the profile URL, or "me". The code will usually be in r.FormValue("code"), but before calling this method be sure to check the value of r.FormValue("state") is as expected.

func (*AuthenticationConfig) RedirectURL

func (c *AuthenticationConfig) RedirectURL(endpoints Endpoints, me, state string) string

RedirectURL returns a URL to the authorization provider for the profile URL, or "me", given.

type AuthorizationConfig

type AuthorizationConfig struct {
	ClientID    *url.URL
	RedirectURI *url.URL
	Scopes      []string
	Client      *http.Client
}

AuthorizationConfig defines configuration for a client making requests to authorize a user to perform a set of defined actions.

func Authorization

func Authorization(clientID, redirectURI string, scopes []string) (*AuthorizationConfig, error)
Example
package main

import (
	"net/http"

	"hawx.me/code/indieauth"
)

func main() {
	randomString := func() string {
		return "abcde"
	}

	setCookie := func(w http.ResponseWriter, r *http.Request, token indieauth.Token) {
		// more code...
	}

	sessions := map[string]indieauth.Endpoints{}
	mes := map[string]string{}

	// get the configuration for authorization, the only difference to
	// authentication is that we are asking the user to allow us to perform
	// certain actions: here 'create' and 'update'
	config, _ := indieauth.Authorization(
		"http://client.example.com/",
		"http://client.example.com/callback",
		[]string{"create", "update"})

	http.HandleFunc("/sign-in", func(w http.ResponseWriter, r *http.Request) {
		state := randomString()

		endpoints, _ := indieauth.FindEndpoints(r.FormValue("me"))
		sessions[state] = endpoints
		// we need to store the user's profile URL as it is needed for the exchange
		// in this flow
		mes[state] = r.FormValue("me")

		redirectURL := config.RedirectURL(endpoints, r.FormValue("me"), "some-random-state")

		http.Redirect(w, r, redirectURL, http.StatusFound)
	})

	http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
		state := r.FormValue("state")

		endpoints, ok := sessions[state]
		if !ok {
			http.Redirect(w, r, "/", http.StatusFound)
			return
		}
		me := mes[state]

		// authorization results in a token which we can then use to perform actions
		// on behalf of the authenticated user
		token, err := config.Exchange(endpoints, r.FormValue("code"), me)
		if err != nil {
			http.Redirect(w, r, "/?error", http.StatusFound)
			return
		}

		setCookie(w, r, token)
		http.Redirect(w, r, "/", http.StatusFound)
	})
}
Output:

func (*AuthorizationConfig) Exchange

func (c *AuthorizationConfig) Exchange(endpoints Endpoints, code, me string) (token Token, err error)

Exchange converts an authorization code into a token. The code will usually be in r.FormValue("code"), but before calling this method be sure to check the value of r.FormValue("state") is as expected.

func (*AuthorizationConfig) RedirectURL

func (c *AuthorizationConfig) RedirectURL(endpoints Endpoints, me, state string) string

RedirectURL returns a URL to the authorization provider for the profile URL, or "me", given.

type Endpoints

type Endpoints struct {
	Authorization *url.URL
	Token         *url.URL
}

func FindEndpoints

func FindEndpoints(me string) (ends Endpoints, err error)

type Token

type Token struct {
	AccessToken string
	TokenType   string
	Scopes      []string
	Me          string
}

Token can be used to make requests on behalf of the user who provided authorization to the client.

func (Token) HasScope

func (t Token) HasScope(scope string) bool

HasScope returns true if the token was issued with the scope.

Directories

Path Synopsis
Package sessions implements some helpers for getting started with indieauth.
Package sessions implements some helpers for getting started with indieauth.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL