connectauth

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2023 License: Apache-2.0 Imports: 4 Imported by: 0

README

connectauth

Build Report Card GoDoc

connectauth provides an authentication interceptor for connect-go. It works with any authentication function and covers both unary and streaming RPCs.

Using an RPC interceptor makes it easy to send detailed errors to gRPC and Connect clients: you can assign error codes, add metadata, or attach error details. However, keep in mind that Connect produces plain net/http handlers that work with any HTTP middleware: for example, you could use Auth0's HTTP middleware for JWT validation.

Status and support

connectauth supports the most recent major release of Go. It's currently unstable, but I hope to cut a stable 1.0 by mid-2023.

Offered under the Apache 2 license.

Documentation

Overview

Package connectauth provides a flexible authentication interceptor for github.com/bufbuild/connect-go.

Example
package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/akshayjshah/connectauth"
	"github.com/bufbuild/connect-go"
	"google.golang.org/protobuf/types/known/emptypb"
)

// TestServiceHandler is an interface describing the server-side implementation
// of our example RPC service. It would typically be generated from a protobuf
// schema.
type TestServiceHandler interface {
	GetEmpty(context.Context, *connect.Request[emptypb.Empty]) (*connect.Response[emptypb.Empty], error)
}

// NewTestServiceHandler constructs an HTTP handler. It would typically be
// generated from a protobuf schema.
func NewTestServiceHandler(svc TestServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
	const root = "/connectauth.example.v1.TestService/"
	mux := http.NewServeMux()
	mux.Handle(root+"GetEmpty", connect.NewUnaryHandler(
		root+"GetEmpty",
		svc.GetEmpty,
		opts...,
	))
	return root, mux
}

// service implements TestServiceHandler. You'd typically hand-write this to
// implement your service's application logic.
type service struct{}

func (s *service) GetEmpty(
	ctx context.Context,
	_ *connect.Request[emptypb.Empty],
) (*connect.Response[emptypb.Empty], error) {
	// Your application logic has access to the authenticated identity.
	fmt.Println(connectauth.GetIdentity(ctx))
	return connect.NewResponse(&emptypb.Empty{}), nil
}

func main() {
	// We express our authentication logic with a small function.
	authenticate := func(_ context.Context, req *connectauth.Request) (any, error) {
		const magic = "open-sesame"
		if req.Header.Get("Authorization") != "Bearer "+magic {
			// If authentication fails, we return an error. connectauth.Errorf is a
			// convenient shortcut to produce an error coded with
			// connect.CodeUnauthenticated.
			return nil, connectauth.Errorf("try %q as a bearer token instead", magic)
		}
		// Once we've authenticated the request, we can return the authenticated
		// identity. The identity gets attached to the context passed to subsequent
		// interceptors and our service implementation.
		return "Ali Baba", nil
	}
	mux := http.NewServeMux()
	mux.Handle(NewTestServiceHandler(
		&service{},
		connect.WithInterceptors(connectauth.New(authenticate)),
	))
	http.ListenAndServe(":8080", mux)
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Errorf

func Errorf(template string, args ...any) *connect.Error

Errorf is a convenience function that returns an error coded with connect.CodeUnauthenticated.

func GetIdentity

func GetIdentity(ctx context.Context) any

GetIdentity retrieves the authenticated identity, if any, from the request context.

func WithoutIdentity

func WithoutIdentity(ctx context.Context) context.Context

WithoutIdentity strips the authenticated identity, if any, from the provided context.

Types

type Interceptor

type Interceptor struct {
	// contains filtered or unexported fields
}

Interceptor is a server-side authentication interceptor. In addition to rejecting unauthenticated requests, it can optionally attach an identity to context of authenticated requests.

func New

func New(f func(context.Context, *Request) (any, error)) *Interceptor

New constructs a new Interceptor using the supplied authentication function. The authentication function must return an error if the request cannot be authenticated. The error is typically produced with Errorf, but any error will do.

If requests are successfully authenticated, the authentication function may return the authenticated identity. The identity will be attached to the context, so subsequent interceptors and application code may access it with GetIdentity.

Authentication functions must be safe to call concurrently.

func (*Interceptor) WrapStreamingClient added in v0.1.1

func (i *Interceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc

WrapStreamingClient implements connect.Interceptor with a no-op.

func (*Interceptor) WrapStreamingHandler

WrapStreamingHandler implements connect.Interceptor.

func (*Interceptor) WrapUnary

func (i *Interceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc

WrapUnary implements connect.Interceptor.

type Request

type Request struct {
	Spec   connect.Spec
	Peer   connect.Peer
	Header http.Header
}

Request describes a single RPC invocation.

Jump to

Keyboard shortcuts

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