opgo

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 16, 2025 License: MIT Imports: 19 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.12 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,
	}
	sdk, err := opgo.NewHostedSdk(ctx, meta, testui.Callbacks{}, memstore)
	if err != nil {
		log.Fatal(err)
	}

	if err := sdk.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://example.com/cb"},
			GrantTypes:               []string{"authorization_code"},
			TokenEndpointAuthMethod:  "client_secret_basic",
			ResponseTypes:            []string{"code"},
			ClientName:               "test client",
			IdTokenSignedResponseAlg: "RS256",
		},
	}); err != nil {
		log.Fatal(err)
	}

	// Create ServeMux
	setup := opgo.SetupHelper{
		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,
	}
	mux := setup.NewServeMux(sdk)

	// Add provider-specific handlers
	testui.AppendHandlerFunc(mux, sdk)

	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.

Another example, GoogleCloudHostedService example, demonstrates how to host the OPGO service on Google Cloud Platform using Cloud Firestore, Firebase Authentication, and Cloud Run. See examples/GoogleCloudHostedService/README.md for more information, including required environment variables, available endpoints, and the login process.

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_DISCOVERY_PATH            = "/.well-known/openid-configuration"
	DEFAULT_JWKS_PATH                 = "/.well-known/jwks.json"
	DEFAULT_AUTHORIZATION_PATH        = "/authorize"
	DEFAULT_TOKEN_PATH                = "/token"
	DEFAULT_USERINFO_PATH             = "/userinfo"
	DEFAULT_REGISTRATION_PATH         = "/registration"
	DEFAULT_PUSHED_AUTHORIZATION_PATH = "/par"
)

Variables

This section is empty.

Functions

func FapiResourceEndpointMiddleware added in v0.1.0

func FapiResourceEndpointMiddleware(next http.HandlerFunc) http.HandlerFunc

Types

type ClientParam

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

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 RequestInfo added in v0.1.0

type RequestInfo struct {
	// RequestId is the unique identifier for the request.
	RequestId string
	// Client contains metadata about the client making the request.
	Client *oppb.ClientMeta
	// AuthParams contains the authorization parameters for the request.
	AuthParams *oppb.AuthorizationParameters
}

RequestInfo holds information about a request.

type Sdk

type Sdk interface {
	DiscoveryEndpoint(w http.ResponseWriter, r *http.Request)
	JwksEndpoint(w http.ResponseWriter, r *http.Request)
	AuthorizationEndpoint(w http.ResponseWriter, r *http.Request)
	TokenEndpoint(w http.ResponseWriter, r *http.Request)
	UserinfoEndpoint(w http.ResponseWriter, r *http.Request)
	RegistrationEndpoint(w http.ResponseWriter, r *http.Request)
	PushedAuthorizationEndpoint(w http.ResponseWriter, r *http.Request)

	// AuthorizationIssue issues an authorization request.
	// w is the http.ResponseWriter to write the response to.
	// r is the http.Request containing the request data.
	// requestId is the ID of the authorization request.
	// subject is the subject of the authorization request.
	AuthorizationIssue(w http.ResponseWriter, r *http.Request, requestId, subject string)

	// AuthorizationCancel cancels an authorization request.
	// w is the http.ResponseWriter to write the response to.
	// r is the http.Request containing the request data.
	// requestId is the ID of the authorization request to cancel.
	AuthorizationCancel(w http.ResponseWriter, r *http.Request, requestId string)

	// WriteLoginHtml writes the login HTML response.
	// w is the http.ResponseWriter to write the HTML to.
	// r is the http.Request containing the request data.
	// requestId is the ID of the authorization request.
	// callbacks is the SdkCallbacks interface to handle callbacks.
	WriteLoginHtml(w http.ResponseWriter, r *http.Request, requestId string, callbacks SdkCallbacks)

	// GetRequestInfo retrieves information about a request.
	// ctx is the context for the request.
	// requestId is the ID of the request to retrieve information for.
	GetRequestInfo(ctx context.Context, requestId string) (*RequestInfo, error)

	//
	ClientCreate(context.Context, ClientParam) error
	SessionGroupCreate(context.Context, *oppb.SessionGroupCreateRequest) error
	KeyRotate(context.Context, string) error
}

func NewHostedSdk

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

func NewSemiHostedSdk

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

type SdkCallbacks

type SdkCallbacks interface {
	// GetUserClaimsCallback retrieves user claims(json string) for a given subject.
	// ctx is the context for the request.
	// subject is the subject for which to retrieve claims.
	GetUserClaimsCallback(ctx context.Context, subject string) (string, error)

	// WriteLoginHtmlCallback writes the login HTML response.
	// info is the RequestInfo containing request details.
	// It returns an http.HandlerFunc that serves the HTML response.
	WriteLoginHtmlCallback(info *RequestInfo) http.HandlerFunc
}

SdkCallbacks defines the callbacks for the SDK. It includes methods for retrieving user claims and writing login HTML.

type SetupHelper added in v0.1.0

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

func DefaultPaths

func DefaultPaths() *SetupHelper

func (*SetupHelper) NewServeMux added in v0.1.0

func (p *SetupHelper) NewServeMux(sdk Sdk) *http.ServeMux

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