callback

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2024 License: MPL-2.0 Imports: 8 Imported by: 0

README

callback

Go Reference

The callback package includes handlers (http.HandlerFunc) which can be used for the callback leg an OIDC flow. Callback handlers for both the authorization code flow (with optional PKCE) and the implicit flow are provided.


Example snippets...
ctx := context.Background()
// Create a new Config
pc, err := oidc.NewConfig(
	"http://your-issuer.com/",
	"your_client_id",
	"your_client_secret",
	[]oidc.Alg{oidc.RS256},
	[]string{"http://your_redirect_url/auth-code-callback", "http://your_redirect_url/implicit-callback"},
)
if err != nil {
	// handle error
}

// Create a provider
p, err := oidc.NewProvider(pc)
if err != nil {
	// handle error
}
defer p.Done()

// Create a Request for a user's authentication attempt that will use the
// authorization code flow.  (See NewRequest(...) using the WithPKCE and
// WithImplicit options for creating a Request that uses those flows.)
ttl := 2 * time.Minute
authCodeAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/auth-code-callback")
if err != nil {
	// handle error
}

// Create a Request for a user's authentication attempt using an implicit
// flow.
implicitAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/implicit-callback")
if err != nil {
	// handle error
}

// A function to handle successful attempts from callback.
successFn := func(
	state string,
	t oidc.Token,
	w http.ResponseWriter,
	req *http.Request,
) {
	w.WriteHeader(http.StatusOK)
	printableToken := fmt.Sprintf("id_token: %s", string(t.IDToken()))
	_, _ = w.Write([]byte(printableToken))
}

// A function to handle errors and failed attempts from **callback**.
errorFn := func(
	state string,
	r *callback.AuthenErrorResponse,
	e error,
	w http.ResponseWriter,
	req *http.Request,
) {
	if e != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = w.Write([]byte(e.Error()))
		return
	}
	w.WriteHeader(http.StatusUnauthorized)
}

// create the authorization code callback and register it for use.
authCodeCallback, err := AuthCode(ctx, p, &SingleRequestReader{Request: authCodeAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/auth-code-callback", authCodeCallback)

// create an implicit flow callback and register it for use.
implicitCallback, err := Implicit(ctx, p, &SingleRequestReader{Request: implicitAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/implicit-callback", implicitCallback)

Documentation

Overview

callback is a package that provides callbacks (in the form of http.HandlerFunc) for handling OIDC provider responses to authorization code flow (with optional PKCE) and implicit flow authentication attempts.

Example
// Create a new Config
pc, err := oidc.NewConfig(
	"http://your-issuer.com/",
	"your_client_id",
	"your_client_secret",
	[]oidc.Alg{oidc.RS256},
	[]string{"http://your_redirect_url/auth-code-callback", "http://your_redirect_url/implicit-callback"},
)
if err != nil {
	// handle error
}

// Create a provider
p, err := oidc.NewProvider(pc)
if err != nil {
	// handle error
}
defer p.Done()

// Create a Request for a user's authentication attempt that will use the
// authorization code flow.  (See NewRequest(...) using the WithPKCE and
// WithImplicit options for creating a Request that uses those flows.)
ttl := 2 * time.Minute
authCodeAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/auth-code-callback")
if err != nil {
	// handle error
}

// Create a Request for a user's authentication attempt using an implicit
// flow.
implicitAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/implicit-callback")
if err != nil {
	// handle error
}

// Create an authorization code flow callback
// A function to handle successful attempts.
successFn := func(
	state string,
	t oidc.Token,
	w http.ResponseWriter,
	req *http.Request,
) {
	w.WriteHeader(http.StatusOK)
	printableToken := fmt.Sprintf("id_token: %s", string(t.IDToken()))
	_, _ = w.Write([]byte(printableToken))
}
// A function to handle errors and failed attempts.
errorFn := func(
	state string,
	r *AuthenErrorResponse,
	e error,
	w http.ResponseWriter,
	req *http.Request,
) {
	if e != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = w.Write([]byte(e.Error()))
		return
	}
	w.WriteHeader(http.StatusUnauthorized)
}
// create the authorization code callback and register it for use.
authCodeCallback, err := AuthCode(context.Background(), p, &SingleRequestReader{Request: authCodeAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/auth-code-callback", authCodeCallback)

// create an implicit flow callback and register it for use.
implicitCallback, err := Implicit(context.Background(), p, &SingleRequestReader{Request: implicitAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/implicit-callback", implicitCallback)
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuthCode

AuthCode creates an oidc authorization code callback handler which uses a RequestReader to read existing oidc.Request(s) via the request's oidc "state" parameter as a key for the lookup. In additional to the typical authorization code flow, it also handles the authorization code flow with PKCE.

The SuccessResponseFunc is used to create a response when callback is successful.

The ErrorResponseFunc is to create a response when the callback fails.

Example
// Create a new Config
pc, err := oidc.NewConfig(
	"http://your-issuer.com/",
	"your_client_id",
	"your_client_secret",
	[]oidc.Alg{oidc.RS256},
	[]string{"http://your_redirect_url/auth-code-callback"},
)
if err != nil {
	// handle error
}

// Create a provider
p, err := oidc.NewProvider(pc)
if err != nil {
	// handle error
}
defer p.Done()

// Create a Request for a user's authentication attempt that will use the
// authorization code flow.  (See NewRequest(...) using the WithPKCE and
// WithImplicit options for creating a Request that uses those flows.)
ttl := 2 * time.Minute
authCodeAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/auth-code-callback")
if err != nil {
	// handle error
}

// Create an authorization code flow callback
// A function to handle successful attempts.
successFn := func(
	state string,
	t oidc.Token,
	w http.ResponseWriter,
	req *http.Request,
) {
	w.WriteHeader(http.StatusOK)
	printableToken := fmt.Sprintf("id_token: %s", string(t.IDToken()))
	_, _ = w.Write([]byte(printableToken))
}
// A function to handle errors and failed attempts.
errorFn := func(
	state string,
	r *AuthenErrorResponse,
	e error,
	w http.ResponseWriter,
	req *http.Request,
) {
	if e != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = w.Write([]byte(e.Error()))
		return
	}
	w.WriteHeader(http.StatusUnauthorized)
}
// create the authorization code callback and register it for use.
authCodeCallback, err := AuthCode(context.Background(), p, &SingleRequestReader{Request: authCodeAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/auth-code-callback", authCodeCallback)
Output:

func Implicit

Implicit creates an oidc implicit flow callback handler which uses a RequestReader to read existing oidc.Request(s) via the request's oidc "state" parameter as a key for the lookup.

It should be noted that if your OIDC provider supports PKCE, then use it over the implicit flow

The SuccessResponseFunc is used to create a response when callback is successful.

The ErrorResponseFunc is to create a response when the callback fails.

Example
// Create a new Config
pc, err := oidc.NewConfig(
	"http://your-issuer.com/",
	"your_client_id",
	"your_client_secret",
	[]oidc.Alg{oidc.RS256},
	[]string{"http://your_redirect_url/implicit-callback"},
)
if err != nil {
	// handle error
}

// Create a provider
p, err := oidc.NewProvider(pc)
if err != nil {
	// handle error
}
defer p.Done()

// Create a Request for a user's authentication attempt using an implicit
// flow.
ttl := 2 * time.Minute
implicitAttempt, err := oidc.NewRequest(ttl, "http://your_redirect_url/implicit-callback")
if err != nil {
	// handle error
}

// Create an authorization code flow callback
// A function to handle successful attempts.
successFn := func(
	state string,
	t oidc.Token,
	w http.ResponseWriter,
	req *http.Request,
) {
	w.WriteHeader(http.StatusOK)
	printableToken := fmt.Sprintf("id_token: %s", string(t.IDToken()))
	_, _ = w.Write([]byte(printableToken))
}
// A function to handle errors and failed attempts.
errorFn := func(
	state string,
	r *AuthenErrorResponse,
	e error,
	w http.ResponseWriter,
	req *http.Request,
) {
	if e != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = w.Write([]byte(e.Error()))
		return
	}
	w.WriteHeader(http.StatusUnauthorized)
}

// create an implicit flow callback and register it for use.
implicitCallback, err := Implicit(context.Background(), p, &SingleRequestReader{Request: implicitAttempt}, successFn, errorFn)
if err != nil {
	// handle error
}
http.HandleFunc("/implicit-callback", implicitCallback)
Output:

Types

type AuthenErrorResponse

type AuthenErrorResponse struct {
	Error       string
	Description string
	Uri         string
}

AuthenErrorResponse represents Oauth2 error responses. See: https://openid.net/specs/openid-connect-core-1_0.html#AuthError

type ErrorResponseFunc

type ErrorResponseFunc func(state string, respErr *AuthenErrorResponse, e error, w http.ResponseWriter, req *http.Request)

ErrorResponseFunc is used by Callbacks to create a http response when the callback fails.

The function receives the state returned as part of the oidc authentication response. It also gets parameters for the oidc authentication error response and/or the callback error raised while processing the request. The function should use the http.ResponseWriter to send back whatever content (headers, html, JSON, etc) it wishes to the client that originated the oidc flow.

Just a reminder that the function parameters could also be used to update the oidc.Request for the request or log info about the request, if the implementation requires it.

type RequestReader

type RequestReader interface {
	// Read an existing Request entry.  The returned request's State()
	// must match the state used to look it up. Implementations must be
	// concurrently safe, which likely means returning a deep copy.
	Read(ctx context.Context, state string) (oidc.Request, error)
}

RequestReader defines an interface for finding and reading an oidc.Request

Implementations must be concurrently safe, since the reader will likely be used within a concurrent http.Handler

type SingleRequestReader

type SingleRequestReader struct {
	Request oidc.Request
}

SingleRequestReader implements the RequestReader interface for a single request. It is concurrently safe.

func (*SingleRequestReader) Read

func (sr *SingleRequestReader) Read(ctx context.Context, state string) (oidc.Request, error)

Read() will return it's single-request if the state matches it's Request.State(), otherwise it returns an error of oidc.ErrNotFound. It satisfies the RequestReader interface. Read() is concurrently safe.

type SuccessResponseFunc

type SuccessResponseFunc func(state string, t oidc.Token, w http.ResponseWriter, req *http.Request)

SuccessResponseFunc is used by Callbacks to create a http response when the callback is successful.

The function state parameter will contain the state that was returned as part of a successful oidc authentication response. The oidc.Token is the result of a successful token exchange with the provider. The function should use the http.ResponseWriter to send back whatever content (headers, html, JSON, etc) it wishes to the client that originated the oidc flow.

Just a reminder that the function parameters could also be used to update the oidc.Request for the request or log info about the request, if the implementation requires it.

Jump to

Keyboard shortcuts

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