158 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
package auth
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"errors"
 | 
						|
	"net/http"
 | 
						|
 | 
						|
	"github.com/pocketbase/pocketbase/tools/types"
 | 
						|
	"golang.org/x/oauth2"
 | 
						|
)
 | 
						|
 | 
						|
// ProviderFactoryFunc defines a function for initializing a new OAuth2 provider.
 | 
						|
type ProviderFactoryFunc func() Provider
 | 
						|
 | 
						|
// Providers defines a map with all of the available OAuth2 providers.
 | 
						|
//
 | 
						|
// To register a new provider append a new entry in the map.
 | 
						|
var Providers = map[string]ProviderFactoryFunc{}
 | 
						|
 | 
						|
// NewProviderByName returns a new preconfigured provider instance by its name identifier.
 | 
						|
func NewProviderByName(name string) (Provider, error) {
 | 
						|
	factory, ok := Providers[name]
 | 
						|
	if !ok {
 | 
						|
		return nil, errors.New("missing provider " + name)
 | 
						|
	}
 | 
						|
 | 
						|
	return factory(), nil
 | 
						|
}
 | 
						|
 | 
						|
// Provider defines a common interface for an OAuth2 client.
 | 
						|
type Provider interface {
 | 
						|
	// Context returns the context associated with the provider (if any).
 | 
						|
	Context() context.Context
 | 
						|
 | 
						|
	// SetContext assigns the specified context to the current provider.
 | 
						|
	SetContext(ctx context.Context)
 | 
						|
 | 
						|
	// PKCE indicates whether the provider can use the PKCE flow.
 | 
						|
	PKCE() bool
 | 
						|
 | 
						|
	// SetPKCE toggles the state whether the provider can use the PKCE flow or not.
 | 
						|
	SetPKCE(enable bool)
 | 
						|
 | 
						|
	// DisplayName usually returns provider name as it is officially written
 | 
						|
	// and it could be used directly in the UI.
 | 
						|
	DisplayName() string
 | 
						|
 | 
						|
	// SetDisplayName sets the provider's display name.
 | 
						|
	SetDisplayName(displayName string)
 | 
						|
 | 
						|
	// Scopes returns the provider access permissions that will be requested.
 | 
						|
	Scopes() []string
 | 
						|
 | 
						|
	// SetScopes sets the provider access permissions that will be requested later.
 | 
						|
	SetScopes(scopes []string)
 | 
						|
 | 
						|
	// ClientId returns the provider client's app ID.
 | 
						|
	ClientId() string
 | 
						|
 | 
						|
	// SetClientId sets the provider client's ID.
 | 
						|
	SetClientId(clientId string)
 | 
						|
 | 
						|
	// ClientSecret returns the provider client's app secret.
 | 
						|
	ClientSecret() string
 | 
						|
 | 
						|
	// SetClientSecret sets the provider client's app secret.
 | 
						|
	SetClientSecret(secret string)
 | 
						|
 | 
						|
	// RedirectURL returns the end address to redirect the user
 | 
						|
	// going through the OAuth flow.
 | 
						|
	RedirectURL() string
 | 
						|
 | 
						|
	// SetRedirectURL sets the provider's RedirectURL.
 | 
						|
	SetRedirectURL(url string)
 | 
						|
 | 
						|
	// AuthURL returns the provider's authorization service url.
 | 
						|
	AuthURL() string
 | 
						|
 | 
						|
	// SetAuthURL sets the provider's AuthURL.
 | 
						|
	SetAuthURL(url string)
 | 
						|
 | 
						|
	// TokenURL returns the provider's token exchange service url.
 | 
						|
	TokenURL() string
 | 
						|
 | 
						|
	// SetTokenURL sets the provider's TokenURL.
 | 
						|
	SetTokenURL(url string)
 | 
						|
 | 
						|
	// UserInfoURL returns the provider's user info api url.
 | 
						|
	UserInfoURL() string
 | 
						|
 | 
						|
	// SetUserInfoURL sets the provider's UserInfoURL.
 | 
						|
	SetUserInfoURL(url string)
 | 
						|
 | 
						|
	// Extra returns a shallow copy of any custom config data
 | 
						|
	// that the provider may be need.
 | 
						|
	Extra() map[string]any
 | 
						|
 | 
						|
	// SetExtra updates the provider's custom config data.
 | 
						|
	SetExtra(data map[string]any)
 | 
						|
 | 
						|
	// Client returns an http client using the provided token.
 | 
						|
	Client(token *oauth2.Token) *http.Client
 | 
						|
 | 
						|
	// BuildAuthURL returns a URL to the provider's consent page
 | 
						|
	// that asks for permissions for the required scopes explicitly.
 | 
						|
	BuildAuthURL(state string, opts ...oauth2.AuthCodeOption) string
 | 
						|
 | 
						|
	// FetchToken converts an authorization code to token.
 | 
						|
	FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)
 | 
						|
 | 
						|
	// FetchRawUserInfo requests and marshalizes into `result` the
 | 
						|
	// the OAuth user api response.
 | 
						|
	FetchRawUserInfo(token *oauth2.Token) ([]byte, error)
 | 
						|
 | 
						|
	// FetchAuthUser is similar to FetchRawUserInfo, but normalizes and
 | 
						|
	// marshalizes the user api response into a standardized AuthUser struct.
 | 
						|
	FetchAuthUser(token *oauth2.Token) (user *AuthUser, err error)
 | 
						|
}
 | 
						|
 | 
						|
// wrapFactory is a helper that wraps a Provider specific factory
 | 
						|
// function and returns its result as Provider interface.
 | 
						|
func wrapFactory[T Provider](factory func() T) ProviderFactoryFunc {
 | 
						|
	return func() Provider {
 | 
						|
		return factory()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// AuthUser defines a standardized OAuth2 user data structure.
 | 
						|
type AuthUser struct {
 | 
						|
	Expiry       types.DateTime `json:"expiry"`
 | 
						|
	RawUser      map[string]any `json:"rawUser"`
 | 
						|
	Id           string         `json:"id"`
 | 
						|
	Name         string         `json:"name"`
 | 
						|
	Username     string         `json:"username"`
 | 
						|
	Email        string         `json:"email"`
 | 
						|
	AvatarURL    string         `json:"avatarURL"`
 | 
						|
	AccessToken  string         `json:"accessToken"`
 | 
						|
	RefreshToken string         `json:"refreshToken"`
 | 
						|
 | 
						|
	// @todo
 | 
						|
	// deprecated: use AvatarURL instead
 | 
						|
	// AvatarUrl will be removed after dropping v0.22 support
 | 
						|
	AvatarUrl string `json:"avatarUrl"`
 | 
						|
}
 | 
						|
 | 
						|
// MarshalJSON implements the [json.Marshaler] interface.
 | 
						|
//
 | 
						|
// @todo remove after dropping v0.22 support
 | 
						|
func (au AuthUser) MarshalJSON() ([]byte, error) {
 | 
						|
	type alias AuthUser // prevent recursion
 | 
						|
 | 
						|
	au2 := alias(au)
 | 
						|
	au2.AvatarUrl = au.AvatarURL // ensure that the legacy field is populated
 | 
						|
 | 
						|
	return json.Marshal(au2)
 | 
						|
}
 |