opgo

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Apr 22, 2025 License: MIT Imports: 17 Imported by: 0

README

opgo

license release Go Report Card

opgo is an SDK for building OpenID Connect Providers (OPs) in Go. Users can create their own OPs by implementing configurations that determine the provider's behavior, user interfaces, user information for authentication, and storage for session states. Alternatively, opgo can be run as an OP simulator using the sample code for developing Relying Parties (RPs).

Features

By utilizing opgo, users can flexibly implement the following elements to build their own OpenID Connect Provider:

  • Configuration: You can implement various settings to determine the provider's behavior.
  • UI: You can implement user interfaces such as authentication and consent screens.
  • User Information: You can implement the management of user information for authentication.
  • Storage: You can implement the persistence of session states and other data.

Additionally, opgo can also function as an OP simulator using the provided sample code for developing Relying Parties (RPs).

Getting Started

Prerequisites
  • Go 1.23.8 or higher
Installation
go get https://github.com/Eigen438/opgo
Basic Usage
func main() {
	ctx := context.Background()
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	issuer := os.Getenv("ISSUER")
	if issuer == "" {
		issuer = "http://localhost:" + port
	}

	// use storage on memory
	memstore := inmemstore.New(1 * time.Minute)
	dataprovider.Initialize(memstore)
	dataprovider.AddWriteOpInterceptor(&model.TokenIdentifier{}, inmemstore.TokenWriteInterceptor)

	meta := &oppb.IssuerMeta{
		Issuer:                            issuer,
		AuthorizationEndpoint:             issuer + opgo.DEFAULT_AUTHORIZATION_PATH,
		TokenEndpoint:                     issuer + opgo.DEFAULT_TOKEN_PATH,
		UserinfoEndpoint:                  issuer + opgo.DEFAULT_USERINFO_PATH,
		JwksUri:                           issuer + opgo.DEFAULT_JWKS_PATH,
		RegistrationEndpoint:              issuer + opgo.DEFAULT_REGISTRATION_PATH,
		ScopesSupported:                   []string{"openid", "profile", "email", "address", "phone", "test", "offline_access"},
		ResponseTypesSupported:            []string{"code", "id_token", "id_token token"},
		GrantTypesSupported:               []string{"authorization_code", "refresh_token", "implicit"},
		AcrValuesSupported:                []string{"urn:mace:incommon:iap:silver"},
		SubjectTypesSupported:             []string{"public"},
		IdTokenSigningAlgValuesSupported:  []string{"none", "RS256"},
		ClaimsSupported:                   []string{"iss"},
		TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post", "client_secret_jwt"},
		RequestParameterSupported:         true,
		RequestUriParameterSupported:      true,
	}
	s, err := opgo.NewHostedSdk(ctx, meta, testui.Callbacks{}, memstore)
	if err != nil {
		log.Fatal(err)
	}

	if err := s.ClientCreate(ctx, opgo.ClientParam{
		ClientId:     "default",
		ClientSecret: "secret",
		Meta: &oppb.ClientMeta{
			// If you do not set the RedirectUris parameter, the check will be skipped.
			// RedirectUris: []string{"https://exsample.com/cb"},
			GrantTypes:               []string{"authorization_code"},
			TokenEndpointAuthMethod:  "client_secret_basic",
			ResponseTypes:            []string{"code"},
			ClientName:               "test client",
			IdTokenSignedResponseAlg: "RS256",
		},
	}); err != nil {
		log.Fatal(err)
	}

	mux := s.ServeMux(&opgo.Paths{
		UseDiscovery:      true,
		AuthorizationPath: opgo.DEFAULT_AUTHORIZATION_PATH,
		TokenPath:         opgo.DEFAULT_TOKEN_PATH,
		UserinfoPath:      opgo.DEFAULT_USERINFO_PATH,
		JwksPath:          opgo.DEFAULT_JWKS_PATH,
		RegistrationPath:  opgo.DEFAULT_REGISTRATION_PATH,
	})
	// Add provider-specific handlers
	mux.HandleFunc("/login", testui.LoginHandler(s))
	mux.HandleFunc("/cancel", testui.CancelHandler(s))

	log.Printf("start server(port:%s)", port)

	server := http.Server{
		Addr: ":" + port,
		Handler: cors.New(cors.Options{
			AllowedHeaders: []string{"*"},
		}).Handler(mux),
	}
	log.Fatal(server.ListenAndServe())
}
The code above performs the following actions:
  • Configuration: Defines the OP metadata in the oppb.IssuerMeta struct.
  • Storage: Initializes an in-memory storage using inmemstore.New and sets it to dataprovider.
  • SDK Initialization: Creates an SDK instance using the opgo.NewHostedSdk function.
  • Client Registration: Registers an initial client using the s.ClientCreate function.
  • Routing: Obtains an http.ServeMux to handle requests to the OP's endpoints using s.ServeMux, and adds custom handlers (/login, /cancel).
  • Server Startup: Starts an HTTP server using the net/http package to handle incoming requests. The server is configured with CORS settings using the cors package to allow all headers.

Customization

When using opgo, users can build their own unique OpenID Connect Provider by implementing and configuring the following aspects:

  • Storage: Besides inmemstore, users can implement persistent storage using databases or other methods.
  • UI: Instead of the testui package, users can implement their own authentication and consent screens.
  • Callbacks: Users can implement callback functions to perform custom logic before and after authentication processes.
  • Configuration: By modifying structs like oppb.IssuerMeta and opgo.ClientParam, users can precisely control the behavior of their OP.

Examples

For a practical example of how to use opgo, check out the LocalHostedService example. This example demonstrates how to set up a locally hosted OpenID Connect Provider using the opgo SDK.

Contributing

Feel free to submit bug reports and feature requests through GitHub Issues. Pull requests are also welcome.

Acknowledgment

The development of opgo was inspired by Authlete. We extend our sincere gratitude to them.

License

MIT License

Copyright (c) 2025 Eigen

Documentation

Index

Constants

View Source
const (
	DEFAULT_AUTHORIZATION_PATH = "/authorize"
	DEFAULT_DISCOVERY_PATH     = "/.well-known/openid-configuration"
	DEFAULT_JWKS_PATH          = "/.well-known/jwks.json"
	DEFAULT_TOKEN_PATH         = "/token"
	DEFAULT_USERINFO_PATH      = "/userinfo"
	DEFAULT_REGISTRATION_PATH  = "/registration"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ClientParam

type ClientParam struct {
	ClientId     string
	ClientSecret string
	Meta         *oppb.ClientMeta
	Attribute    *oppb.ClientAttribute
}

type Config

type Config struct {
	ServerHostPort string       `validate:"required"`
	IssuerId       string       `validate:"required"`
	IssuerPassword string       `validate:"required"`
	Callbacks      SdkCallbacks `validate:"required"`
}

type IssueRequest

type IssueRequest struct {
	RequestId string
	SessionId string
	Subject   string
}

type Paths

type Paths struct {
	UseDiscovery      bool
	AuthorizationPath string
	TokenPath         string
	UserinfoPath      string
	JwksPath          string
	RegistrationPath  string
}

func DefaultPaths

func DefaultPaths() *Paths

type Sdk

type Sdk interface {
	ServeMux(*Paths) *http.ServeMux
	StartSession(*IssueRequest) http.HandlerFunc
	AuthorizationIssue(context.Context, *IssueRequest) (*oppb.AuthorizationIssueResponse, error)
	AuthorizationCancel(context.Context, string) (*oppb.AuthorizationCancelResponse, error)
	GetWriteHtmlParam(context.Context, string) (*WriteHtmlParam, error)
	//
	ClientCreate(context.Context, ClientParam) error
	SessionGroupCreate(context.Context, *oppb.SessionGroupCreateRequest) error
}

func NewHostedSdk

func NewHostedSdk(
	ctx context.Context,
	issuerMeta *oppb.IssuerMeta,
	sdkCallbacks SdkCallbacks,
	providerCallbacks provider.ProviderCallbacks) (Sdk, error)

func NewSemiHostedSdk

func NewSemiHostedSdk(config *Config) (Sdk, error)

type SdkCallbacks

type SdkCallbacks interface {
	GetUserClaimsCallback(ctx context.Context, subject string) (string, error)
	WriteLoginHtmlCallback(param *WriteHtmlParam) http.HandlerFunc
}

type WriteHtmlParam

type WriteHtmlParam struct {
	RequestId  string
	Client     *oppb.ClientMeta
	AuthParams *oppb.AuthorizationParameters
}

Directories

Path Synopsis
examples
internal
pkg
testui
Package testui is a simple user interface for testing opgo.
Package testui is a simple user interface for testing opgo.

Jump to

Keyboard shortcuts

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