indieauth: hawx.me/code/indieauth Index | Examples | Files | Directories

package indieauth

import "hawx.me/code/indieauth"

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

Package Files

authentication.go authorization.go doc.go endpoints.go html.go

type AuthenticationConfig Uses

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 Uses

func Authentication(clientID, redirectURI string) (*AuthenticationConfig, error)

Code:

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)
})

func (*AuthenticationConfig) Exchange Uses

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 Uses

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 Uses

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 Uses

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

Code:

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)
})

func (*AuthorizationConfig) Exchange Uses

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 Uses

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 Uses

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

func FindEndpoints Uses

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

type Token Uses

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 Uses

func (t Token) HasScope(scope string) bool

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

Directories

PathSynopsis
sessionsPackage sessions implements some helpers for getting started with indieauth.

Package indieauth imports 9 packages (graph) and is imported by 14 packages. Updated 2019-11-27. Refresh now. Tools for package owners.