1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-03-21 22:49:42 +02:00
pocketbase/tools/auth/base_provider.go

204 lines
5.3 KiB
Go
Raw Normal View History

2022-07-07 00:19:05 +03:00
package auth
import (
"context"
"fmt"
2022-12-16 17:06:03 +02:00
"io"
"maps"
2022-07-07 00:19:05 +03:00
"net/http"
"golang.org/x/oauth2"
)
2024-09-29 19:23:19 +03:00
// BaseProvider defines common fields and methods used by OAuth2 client providers.
type BaseProvider struct {
2023-03-01 23:29:45 +02:00
ctx context.Context
2022-07-07 00:19:05 +03:00
clientId string
clientSecret string
displayName string
2024-09-29 19:23:19 +03:00
redirectURL string
authURL string
tokenURL string
userInfoURL string
scopes []string
pkce bool
extra map[string]any
2022-07-07 00:19:05 +03:00
}
2023-03-01 23:29:45 +02:00
// Context implements Provider.Context() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) Context() context.Context {
2023-03-01 23:29:45 +02:00
return p.ctx
}
// SetContext implements Provider.SetContext() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetContext(ctx context.Context) {
2023-03-01 23:29:45 +02:00
p.ctx = ctx
}
// PKCE implements Provider.PKCE() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) PKCE() bool {
return p.pkce
}
// SetPKCE implements Provider.SetPKCE() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetPKCE(enable bool) {
p.pkce = enable
}
// DisplayName implements Provider.DisplayName() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) DisplayName() string {
return p.displayName
}
// SetDisplayName implements Provider.SetDisplayName() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetDisplayName(displayName string) {
p.displayName = displayName
}
2023-03-01 23:29:45 +02:00
// Scopes implements Provider.Scopes() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) Scopes() []string {
2022-07-07 00:19:05 +03:00
return p.scopes
}
2023-03-01 23:29:45 +02:00
// SetScopes implements Provider.SetScopes() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetScopes(scopes []string) {
2022-07-07 00:19:05 +03:00
p.scopes = scopes
}
2023-03-01 23:29:45 +02:00
// ClientId implements Provider.ClientId() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) ClientId() string {
2022-07-07 00:19:05 +03:00
return p.clientId
}
2023-03-01 23:29:45 +02:00
// SetClientId implements Provider.SetClientId() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetClientId(clientId string) {
2022-07-07 00:19:05 +03:00
p.clientId = clientId
}
2023-03-01 23:29:45 +02:00
// ClientSecret implements Provider.ClientSecret() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) ClientSecret() string {
2022-07-07 00:19:05 +03:00
return p.clientSecret
}
2023-03-01 23:29:45 +02:00
// SetClientSecret implements Provider.SetClientSecret() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) SetClientSecret(secret string) {
2022-07-07 00:19:05 +03:00
p.clientSecret = secret
}
2024-09-29 19:23:19 +03:00
// RedirectURL implements Provider.RedirectURL() interface method.
func (p *BaseProvider) RedirectURL() string {
return p.redirectURL
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// SetRedirectURL implements Provider.SetRedirectURL() interface method.
func (p *BaseProvider) SetRedirectURL(url string) {
p.redirectURL = url
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// AuthURL implements Provider.AuthURL() interface method.
func (p *BaseProvider) AuthURL() string {
return p.authURL
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// SetAuthURL implements Provider.SetAuthURL() interface method.
func (p *BaseProvider) SetAuthURL(url string) {
p.authURL = url
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// TokenURL implements Provider.TokenURL() interface method.
func (p *BaseProvider) TokenURL() string {
return p.tokenURL
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// SetTokenURL implements Provider.SetTokenURL() interface method.
func (p *BaseProvider) SetTokenURL(url string) {
p.tokenURL = url
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// UserInfoURL implements Provider.UserInfoURL() interface method.
func (p *BaseProvider) UserInfoURL() string {
return p.userInfoURL
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// SetUserInfoURL implements Provider.SetUserInfoURL() interface method.
func (p *BaseProvider) SetUserInfoURL(url string) {
p.userInfoURL = url
2022-07-07 00:19:05 +03:00
}
// Extra implements Provider.Extra() interface method.
func (p *BaseProvider) Extra() map[string]any {
return maps.Clone(p.extra)
}
// SetExtra implements Provider.SetExtra() interface method.
func (p *BaseProvider) SetExtra(data map[string]any) {
p.extra = data
}
2024-09-29 19:23:19 +03:00
// BuildAuthURL implements Provider.BuildAuthURL() interface method.
func (p *BaseProvider) BuildAuthURL(state string, opts ...oauth2.AuthCodeOption) string {
2022-07-07 00:19:05 +03:00
return p.oauth2Config().AuthCodeURL(state, opts...)
}
2023-03-01 23:29:45 +02:00
// FetchToken implements Provider.FetchToken() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
2023-03-01 23:29:45 +02:00
return p.oauth2Config().Exchange(p.ctx, code, opts...)
2022-07-07 00:19:05 +03:00
}
2023-03-01 23:29:45 +02:00
// Client implements Provider.Client() interface method.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) Client(token *oauth2.Token) *http.Client {
2023-03-01 23:29:45 +02:00
return p.oauth2Config().Client(p.ctx, token)
2022-07-07 00:19:05 +03:00
}
2024-09-29 19:23:19 +03:00
// FetchRawUserInfo implements Provider.FetchRawUserInfo() interface method.
func (p *BaseProvider) FetchRawUserInfo(token *oauth2.Token) ([]byte, error) {
req, err := http.NewRequestWithContext(p.ctx, "GET", p.userInfoURL, nil)
2022-11-13 14:20:11 +02:00
if err != nil {
return nil, err
2022-11-13 14:20:11 +02:00
}
2024-09-29 19:23:19 +03:00
return p.sendRawUserInfoRequest(req, token)
2022-11-13 14:20:11 +02:00
}
2024-09-29 19:23:19 +03:00
// sendRawUserInfoRequest sends the specified user info request and return its raw response body.
func (p *BaseProvider) sendRawUserInfoRequest(req *http.Request, token *oauth2.Token) ([]byte, error) {
2022-07-07 00:19:05 +03:00
client := p.Client(token)
2023-03-01 23:29:45 +02:00
res, err := client.Do(req)
2022-07-07 00:19:05 +03:00
if err != nil {
return nil, err
2022-07-07 00:19:05 +03:00
}
2023-03-01 23:29:45 +02:00
defer res.Body.Close()
2022-07-07 00:19:05 +03:00
2023-03-01 23:29:45 +02:00
result, err := io.ReadAll(res.Body)
2022-07-07 00:19:05 +03:00
if err != nil {
return nil, err
2022-07-07 00:19:05 +03:00
}
// http.Client.Get doesn't treat non 2xx responses as error
2023-03-01 23:29:45 +02:00
if res.StatusCode >= 400 {
return nil, fmt.Errorf(
2023-03-01 23:29:45 +02:00
"failed to fetch OAuth2 user profile via %s (%d):\n%s",
2024-09-29 19:23:19 +03:00
p.userInfoURL,
2023-03-01 23:29:45 +02:00
res.StatusCode,
string(result),
)
}
return result, nil
2022-07-07 00:19:05 +03:00
}
// oauth2Config constructs a oauth2.Config instance based on the provider settings.
2024-09-29 19:23:19 +03:00
func (p *BaseProvider) oauth2Config() *oauth2.Config {
2022-07-07 00:19:05 +03:00
return &oauth2.Config{
2024-09-29 19:23:19 +03:00
RedirectURL: p.redirectURL,
2022-07-07 00:19:05 +03:00
ClientID: p.clientId,
ClientSecret: p.clientSecret,
Scopes: p.scopes,
Endpoint: oauth2.Endpoint{
2024-09-29 19:23:19 +03:00
AuthURL: p.authURL,
TokenURL: p.tokenURL,
2022-07-07 00:19:05 +03:00
},
}
}