oauth2w

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2021 License: MIT Imports: 5 Imported by: 0

README

oauth2w

GoDoc Build Status codecov Go Report Card

oauth2w is a HTTP middleware that enables authorization via the OpenID Connect protocol.

Installation

go get github.com/i-core/oauth2w

How it works

  1. A client sends HTTP request that contains an OpenID Connect Access Token within the header Authorization.
  2. The middleware requests user claims using the userinfo's endpoint of OpenID Connect Provider.
  3. The middleware requests user roles using the interface oauth2w.RoleFinder.
  4. The middleware validates that the user has the required roles, and according to it, allows or not the HTTP request.

Note 1. Getting user roles is out of scope the library. You must provide an implementation of oauth2w.RoleFinder that receives user claims and returns the user's roles.

Note 2. The middleware add the default role "_default" to each authenticated user. You can use it in order to transparently add an access to endpoints that each authenticated user must have an access for.

Usage

Simple
package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/i-core/oauth2w"
)

const oidcEndpoint = "https://openid-connect-provider.org"

func main() {
    authw, err := oauth2w.New(oidcEndpoint, &RoleFinder{})
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    http.HandleFunc("/profile", authw([]string{"user"})(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Profile page")
    }))
    http.HandleFunc("/admin", authw([]string{"admin"})(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Admin page")
    }))

    fmt.Println(http.ListenAndServe(":8080", nil))
}

// RoleFinder finds user roles in the user's claims.
type RoleFinder struct {}
func (f *RoleFinder) FindRoles(claims map[string]interface{}) ([]string, error) {
    roleClaim, ok := claims['roles']
    if !ok {
        return nil, nil
    }
    roles, ok := roleClaim.([]interface{})
    !ok {
        return nil, fmt.Errorf("invalid role claim \"roles\"")
    }
    var vv []string
    for _, role := range roles {
        s, ok := role.(string)
        if !ok {
            return nil, fmt.Errorf("invalid role claim \"roles\"")
        }
        vv = append(vv, s)
    }
    return vv, nil
}
Logging
package main

import (
    "fmt"

    "github.com/i-core/oauth2w"
)

const oidcEndpoint = "https://openid-connect-provider.org"

func main() {
    logPrintFn := func(ctx context.Context) func(string, ...interface{}) {
        return func(msg string, keysAndValues ...interface{}) {
            params = append([]interface{}{"Info:", msg}, ...keysAndValues)
            fmt.Println(params...)
        }
    }
    logDebugFn := func(ctx context.Context) func(string, ...interface{}) {
        return func(msg string, keysAndValues ...interface{}) {
            params = append([]interface{}{"Debug:", msg}, ...keysAndValues)
            fmt.Println(params...)
        }
    }
    authw, err := oauth2w.New(oidcEndpoint, &RoleFinder{}, oauth2w.WithLogPrint(logPrintFn), oauth2w.WithLogDebug(logDebugFn))
    // ...
}
Accessing user data
package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/i-core/oauth2w"
)

const oidcEndpoint = "https://openid-connect-provider.org"

func main() {
    authw, err := oauth2w.New(oidcEndpoint, &RoleFinder{})
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    http.HandleFunc("/profile", authw(func(w http.ResponseWriter, r *http.Request) {
        user := oauth2w.FindUser(r.Context())
        fmt.Printf("User %v\n", user)
    }))
    fmt.Println(http.ListenAndServe(":8080", nil))
}
Usage with Ory Hydra and Werther

When you use OpenID Connect Provider ORY Hydra with Identity Provider Werther you can use an implementation of RoleFinder from package github.com/i-core/oauth2w/werther.

With the default role claim:

package main

import (
    "github.com/i-core/oauth2w"
    "github.com/i-core/oauth2w/werther"
)

const (
    oidcEndpoint = "https://openid-connect-provider.org"
    roleGroupID  = "myapp"
)

func main() {
    authw, err := oauth2w.New(oidcEndpoint, werther.NewRoleFinder(roleGroupID))
    // ...
}

With a custom name of the role claim:

package main

import (
    "github.com/i-core/oauth2w"
    "github.com/i-core/oauth2w/werther"
)

const (
    oidcEndpoint = "https://openid-connect-provider.org"
    roleClaim    = "http://my-company.org/claims/roles"
    roleGroupID  = "myapp"
)

func main() {
    authw, err := oauth2w.New(oidcEndpoint, werther.NewRoleFinder(roleGroupID).WithRoleClaim(roleClaim))
    // ...
}

Contributing

Thanks for your interest in contributing to this project. Get started with our Contributing Guide.

License

The code in this project is licensed under MIT license.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(endpoint string, roleFinder RoleFinder, opts ...Option) (func([]string) func(http.Handler) http.Handler, error)

New returns a new instance of the middleware.

To authorize HTTP request the middleware validates that the user has all required roles. When there is no required roles the middleware authorizes all HTTP requests.

To get user roles the middleware requests user claims from an OpenID Connect Provider, and then transforms the claims to roles using the interface RoleFinder.

endpoint is an endpoint of an OpenID Connect Provider.

Types

type LogFn

type LogFn func(context.Context) func(string, ...interface{})

LogFn is a function that provides a logging function for HTTP request.

type Option

type Option func(*config)

Option describes a function for the middleware's configuration.

func WithLogDebug

func WithLogDebug(logFn LogFn) Option

WithLogDebug returns an option that configures a debug logger.

func WithLogPrint

func WithLogPrint(logFn LogFn) Option

WithLogPrint returns an option that configures an info logger.

type RoleFinder

type RoleFinder interface {
	FindRoles(claims map[string]interface{}) ([]string, error)
}

RoleFinder is an interface to find user roles using the user's claims.

type User added in v1.1.0

type User struct {
	Email string
	Roles []string
}

User contains data of an authenticated user.

func FindUser added in v1.1.0

func FindUser(ctx context.Context) *User

FindUser returs data of an authenticated user from the request context.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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