merge v0.23.0-rc changes

This commit is contained in:
Gani Georgiev
2024-09-29 19:23:19 +03:00
parent ad92992324
commit 844f18cac3
753 changed files with 85141 additions and 63396 deletions
+14 -10
View File
@@ -18,6 +18,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameApple] = wrapFactory(NewAppleProvider)
}
var _ Provider = (*Apple)(nil)
// NameApple is the unique name of the Apple provider.
@@ -27,23 +31,23 @@ const NameApple string = "apple"
//
// [OIDC differences]: https://bitbucket.org/openid/connect/src/master/How-Sign-in-with-Apple-differs-from-OpenID-Connect.md
type Apple struct {
*baseProvider
BaseProvider
jwksUrl string
jwksURL string
}
// NewAppleProvider creates a new Apple provider instance with some defaults.
func NewAppleProvider() *Apple {
return &Apple{
baseProvider: &baseProvider{
BaseProvider: BaseProvider{
ctx: context.Background(),
displayName: "Apple",
pkce: true,
scopes: []string{"name", "email"},
authUrl: "https://appleid.apple.com/auth/authorize",
tokenUrl: "https://appleid.apple.com/auth/token",
authURL: "https://appleid.apple.com/auth/authorize",
tokenURL: "https://appleid.apple.com/auth/token",
},
jwksUrl: "https://appleid.apple.com/auth/keys",
jwksURL: "https://appleid.apple.com/auth/keys",
}
}
@@ -51,7 +55,7 @@ func NewAppleProvider() *Apple {
//
// API reference: https://developer.apple.com/documentation/sign_in_with_apple/tokenresponse.
func (p *Apple) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -98,11 +102,11 @@ func (p *Apple) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
return user, nil
}
// FetchRawUserData implements Provider.FetchRawUserData interface.
// FetchRawUserInfo implements Provider.FetchRawUserInfo interface.
//
// Apple doesn't have a UserInfo endpoint and claims about users
// are instead included in the "id_token" (https://openid.net/specs/openid-connect-core-1_0.html#id_tokenExample)
func (p *Apple) FetchRawUserData(token *oauth2.Token) ([]byte, error) {
func (p *Apple) FetchRawUserInfo(token *oauth2.Token) ([]byte, error) {
idToken, _ := token.Extra("id_token").(string)
claims, err := p.parseAndVerifyIdToken(idToken)
@@ -209,7 +213,7 @@ type jwk struct {
}
func (p *Apple) fetchJWK(kid string) (*jwk, error) {
req, err := http.NewRequestWithContext(p.ctx, "GET", p.jwksUrl, nil)
req, err := http.NewRequestWithContext(p.ctx, "GET", p.jwksURL, nil)
if err != nil {
return nil, err
}
+73 -87
View File
@@ -2,6 +2,7 @@ package auth
import (
"context"
"encoding/json"
"errors"
"net/http"
@@ -9,17 +10,22 @@ import (
"golang.org/x/oauth2"
)
// AuthUser defines a standardized oauth2 user data structure.
type AuthUser struct {
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"`
Expiry types.DateTime `json:"expiry"`
RawUser map[string]any `json:"rawUser"`
// 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.
@@ -61,104 +67,84 @@ type Provider interface {
// SetClientSecret sets the provider client's app secret.
SetClientSecret(secret string)
// RedirectUrl returns the end address to redirect the user
// RedirectURL returns the end address to redirect the user
// going through the OAuth flow.
RedirectUrl() string
RedirectURL() string
// SetRedirectUrl sets the provider's RedirectUrl.
SetRedirectUrl(url string)
// SetRedirectURL sets the provider's RedirectURL.
SetRedirectURL(url string)
// AuthUrl returns the provider's authorization service url.
AuthUrl() string
// AuthURL returns the provider's authorization service url.
AuthURL() string
// SetAuthUrl sets the provider's AuthUrl.
SetAuthUrl(url string)
// SetAuthURL sets the provider's AuthURL.
SetAuthURL(url string)
// TokenUrl returns the provider's token exchange service url.
TokenUrl() string
// TokenURL returns the provider's token exchange service url.
TokenURL() string
// SetTokenUrl sets the provider's TokenUrl.
SetTokenUrl(url string)
// SetTokenURL sets the provider's TokenURL.
SetTokenURL(url string)
// UserApiUrl returns the provider's user info api url.
UserApiUrl() string
// UserInfoURL returns the provider's user info api url.
UserInfoURL() string
// SetUserApiUrl sets the provider's UserApiUrl.
SetUserApiUrl(url string)
// SetUserInfoURL sets the provider's UserInfoURL.
SetUserInfoURL(url string)
// 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
// 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
BuildAuthURL(state string, opts ...oauth2.AuthCodeOption) string
// FetchToken converts an authorization code to token.
FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)
// FetchRawUserData requests and marshalizes into `result` the
// FetchRawUserInfo requests and marshalizes into `result` the
// the OAuth user api response.
FetchRawUserData(token *oauth2.Token) ([]byte, error)
FetchRawUserInfo(token *oauth2.Token) ([]byte, error)
// FetchAuthUser is similar to FetchRawUserData, but normalizes and
// 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)
}
// NewProviderByName returns a new preconfigured provider instance by its name identifier.
func NewProviderByName(name string) (Provider, error) {
switch name {
case NameGoogle:
return NewGoogleProvider(), nil
case NameFacebook:
return NewFacebookProvider(), nil
case NameGithub:
return NewGithubProvider(), nil
case NameGitlab:
return NewGitlabProvider(), nil
case NameDiscord:
return NewDiscordProvider(), nil
case NameTwitter:
return NewTwitterProvider(), nil
case NameMicrosoft:
return NewMicrosoftProvider(), nil
case NameSpotify:
return NewSpotifyProvider(), nil
case NameKakao:
return NewKakaoProvider(), nil
case NameTwitch:
return NewTwitchProvider(), nil
case NameStrava:
return NewStravaProvider(), nil
case NameGitee:
return NewGiteeProvider(), nil
case NameLivechat:
return NewLivechatProvider(), nil
case NameGitea:
return NewGiteaProvider(), nil
case NameOIDC:
return NewOIDCProvider(), nil
case NameOIDC + "2":
return NewOIDCProvider(), nil
case NameOIDC + "3":
return NewOIDCProvider(), nil
case NameApple:
return NewAppleProvider(), nil
case NameInstagram:
return NewInstagramProvider(), nil
case NameVK:
return NewVKProvider(), nil
case NameYandex:
return NewYandexProvider(), nil
case NamePatreon:
return NewPatreonProvider(), nil
case NameMailcow:
return NewMailcowProvider(), nil
case NameBitbucket:
return NewBitbucketProvider(), nil
case NamePlanningcenter:
return NewPlanningcenterProvider(), nil
default:
return nil, errors.New("Missing provider " + name)
// 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)
}
+8
View File
@@ -6,6 +6,14 @@ import (
"github.com/pocketbase/pocketbase/tools/auth"
)
func TestProvidersCount(t *testing.T) {
expected := 25
if total := len(auth.Providers); total != expected {
t.Fatalf("Expected %d providers, got %d", expected, total)
}
}
func TestNewProviderByName(t *testing.T) {
var err error
var p auth.Provider
+57 -57
View File
@@ -9,147 +9,147 @@ import (
"golang.org/x/oauth2"
)
// baseProvider defines common fields and methods used by OAuth2 client providers.
type baseProvider struct {
// BaseProvider defines common fields and methods used by OAuth2 client providers.
type BaseProvider struct {
ctx context.Context
clientId string
clientSecret string
displayName string
redirectUrl string
authUrl string
tokenUrl string
userApiUrl string
redirectURL string
authURL string
tokenURL string
userInfoURL string
scopes []string
pkce bool
}
// Context implements Provider.Context() interface method.
func (p *baseProvider) Context() context.Context {
func (p *BaseProvider) Context() context.Context {
return p.ctx
}
// SetContext implements Provider.SetContext() interface method.
func (p *baseProvider) SetContext(ctx context.Context) {
func (p *BaseProvider) SetContext(ctx context.Context) {
p.ctx = ctx
}
// PKCE implements Provider.PKCE() interface method.
func (p *baseProvider) PKCE() bool {
func (p *BaseProvider) PKCE() bool {
return p.pkce
}
// SetPKCE implements Provider.SetPKCE() interface method.
func (p *baseProvider) SetPKCE(enable bool) {
func (p *BaseProvider) SetPKCE(enable bool) {
p.pkce = enable
}
// DisplayName implements Provider.DisplayName() interface method.
func (p *baseProvider) DisplayName() string {
func (p *BaseProvider) DisplayName() string {
return p.displayName
}
// SetDisplayName implements Provider.SetDisplayName() interface method.
func (p *baseProvider) SetDisplayName(displayName string) {
func (p *BaseProvider) SetDisplayName(displayName string) {
p.displayName = displayName
}
// Scopes implements Provider.Scopes() interface method.
func (p *baseProvider) Scopes() []string {
func (p *BaseProvider) Scopes() []string {
return p.scopes
}
// SetScopes implements Provider.SetScopes() interface method.
func (p *baseProvider) SetScopes(scopes []string) {
func (p *BaseProvider) SetScopes(scopes []string) {
p.scopes = scopes
}
// ClientId implements Provider.ClientId() interface method.
func (p *baseProvider) ClientId() string {
func (p *BaseProvider) ClientId() string {
return p.clientId
}
// SetClientId implements Provider.SetClientId() interface method.
func (p *baseProvider) SetClientId(clientId string) {
func (p *BaseProvider) SetClientId(clientId string) {
p.clientId = clientId
}
// ClientSecret implements Provider.ClientSecret() interface method.
func (p *baseProvider) ClientSecret() string {
func (p *BaseProvider) ClientSecret() string {
return p.clientSecret
}
// SetClientSecret implements Provider.SetClientSecret() interface method.
func (p *baseProvider) SetClientSecret(secret string) {
func (p *BaseProvider) SetClientSecret(secret string) {
p.clientSecret = secret
}
// RedirectUrl implements Provider.RedirectUrl() interface method.
func (p *baseProvider) RedirectUrl() string {
return p.redirectUrl
// RedirectURL implements Provider.RedirectURL() interface method.
func (p *BaseProvider) RedirectURL() string {
return p.redirectURL
}
// SetRedirectUrl implements Provider.SetRedirectUrl() interface method.
func (p *baseProvider) SetRedirectUrl(url string) {
p.redirectUrl = url
// SetRedirectURL implements Provider.SetRedirectURL() interface method.
func (p *BaseProvider) SetRedirectURL(url string) {
p.redirectURL = url
}
// AuthUrl implements Provider.AuthUrl() interface method.
func (p *baseProvider) AuthUrl() string {
return p.authUrl
// AuthURL implements Provider.AuthURL() interface method.
func (p *BaseProvider) AuthURL() string {
return p.authURL
}
// SetAuthUrl implements Provider.SetAuthUrl() interface method.
func (p *baseProvider) SetAuthUrl(url string) {
p.authUrl = url
// SetAuthURL implements Provider.SetAuthURL() interface method.
func (p *BaseProvider) SetAuthURL(url string) {
p.authURL = url
}
// TokenUrl implements Provider.TokenUrl() interface method.
func (p *baseProvider) TokenUrl() string {
return p.tokenUrl
// TokenURL implements Provider.TokenURL() interface method.
func (p *BaseProvider) TokenURL() string {
return p.tokenURL
}
// SetTokenUrl implements Provider.SetTokenUrl() interface method.
func (p *baseProvider) SetTokenUrl(url string) {
p.tokenUrl = url
// SetTokenURL implements Provider.SetTokenURL() interface method.
func (p *BaseProvider) SetTokenURL(url string) {
p.tokenURL = url
}
// UserApiUrl implements Provider.UserApiUrl() interface method.
func (p *baseProvider) UserApiUrl() string {
return p.userApiUrl
// UserInfoURL implements Provider.UserInfoURL() interface method.
func (p *BaseProvider) UserInfoURL() string {
return p.userInfoURL
}
// SetUserApiUrl implements Provider.SetUserApiUrl() interface method.
func (p *baseProvider) SetUserApiUrl(url string) {
p.userApiUrl = url
// SetUserInfoURL implements Provider.SetUserInfoURL() interface method.
func (p *BaseProvider) SetUserInfoURL(url string) {
p.userInfoURL = url
}
// BuildAuthUrl implements Provider.BuildAuthUrl() interface method.
func (p *baseProvider) BuildAuthUrl(state string, opts ...oauth2.AuthCodeOption) string {
// BuildAuthURL implements Provider.BuildAuthURL() interface method.
func (p *BaseProvider) BuildAuthURL(state string, opts ...oauth2.AuthCodeOption) string {
return p.oauth2Config().AuthCodeURL(state, opts...)
}
// FetchToken implements Provider.FetchToken() interface method.
func (p *baseProvider) FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
func (p *BaseProvider) FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
return p.oauth2Config().Exchange(p.ctx, code, opts...)
}
// Client implements Provider.Client() interface method.
func (p *baseProvider) Client(token *oauth2.Token) *http.Client {
func (p *BaseProvider) Client(token *oauth2.Token) *http.Client {
return p.oauth2Config().Client(p.ctx, token)
}
// FetchRawUserData implements Provider.FetchRawUserData() interface method.
func (p *baseProvider) FetchRawUserData(token *oauth2.Token) ([]byte, error) {
req, err := http.NewRequestWithContext(p.ctx, "GET", p.userApiUrl, nil)
// 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)
if err != nil {
return nil, err
}
return p.sendRawUserDataRequest(req, token)
return p.sendRawUserInfoRequest(req, token)
}
// sendRawUserDataRequest sends the specified user data request and return its raw response body.
func (p *baseProvider) sendRawUserDataRequest(req *http.Request, token *oauth2.Token) ([]byte, error) {
// 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) {
client := p.Client(token)
res, err := client.Do(req)
@@ -167,7 +167,7 @@ func (p *baseProvider) sendRawUserDataRequest(req *http.Request, token *oauth2.T
if res.StatusCode >= 400 {
return nil, fmt.Errorf(
"failed to fetch OAuth2 user profile via %s (%d):\n%s",
p.userApiUrl,
p.userInfoURL,
res.StatusCode,
string(result),
)
@@ -177,15 +177,15 @@ func (p *baseProvider) sendRawUserDataRequest(req *http.Request, token *oauth2.T
}
// oauth2Config constructs a oauth2.Config instance based on the provider settings.
func (p *baseProvider) oauth2Config() *oauth2.Config {
func (p *BaseProvider) oauth2Config() *oauth2.Config {
return &oauth2.Config{
RedirectURL: p.redirectUrl,
RedirectURL: p.redirectURL,
ClientID: p.clientId,
ClientSecret: p.clientSecret,
Scopes: p.scopes,
Endpoint: oauth2.Endpoint{
AuthURL: p.authUrl,
TokenURL: p.tokenUrl,
AuthURL: p.authURL,
TokenURL: p.tokenURL,
},
}
}
+52 -52
View File
@@ -8,7 +8,7 @@ import (
)
func TestContext(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.Scopes()
if before != nil {
@@ -24,7 +24,7 @@ func TestContext(t *testing.T) {
}
func TestDisplayName(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.DisplayName()
if before != "" {
@@ -40,7 +40,7 @@ func TestDisplayName(t *testing.T) {
}
func TestPKCE(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.PKCE()
if before != false {
@@ -56,7 +56,7 @@ func TestPKCE(t *testing.T) {
}
func TestScopes(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.Scopes()
if len(before) != 0 {
@@ -72,7 +72,7 @@ func TestScopes(t *testing.T) {
}
func TestClientId(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.ClientId()
if before != "" {
@@ -88,7 +88,7 @@ func TestClientId(t *testing.T) {
}
func TestClientSecret(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
before := b.ClientSecret()
if before != "" {
@@ -103,82 +103,82 @@ func TestClientSecret(t *testing.T) {
}
}
func TestRedirectUrl(t *testing.T) {
b := baseProvider{}
func TestRedirectURL(t *testing.T) {
b := BaseProvider{}
before := b.RedirectUrl()
before := b.RedirectURL()
if before != "" {
t.Fatalf("Expected RedirectUrl to be empty, got %v", before)
t.Fatalf("Expected RedirectURL to be empty, got %v", before)
}
b.SetRedirectUrl("test")
b.SetRedirectURL("test")
after := b.RedirectUrl()
after := b.RedirectURL()
if after != "test" {
t.Fatalf("Expected RedirectUrl to be 'test', got %v", after)
t.Fatalf("Expected RedirectURL to be 'test', got %v", after)
}
}
func TestAuthUrl(t *testing.T) {
b := baseProvider{}
func TestAuthURL(t *testing.T) {
b := BaseProvider{}
before := b.AuthUrl()
before := b.AuthURL()
if before != "" {
t.Fatalf("Expected authUrl to be empty, got %v", before)
t.Fatalf("Expected authURL to be empty, got %v", before)
}
b.SetAuthUrl("test")
b.SetAuthURL("test")
after := b.AuthUrl()
after := b.AuthURL()
if after != "test" {
t.Fatalf("Expected authUrl to be 'test', got %v", after)
t.Fatalf("Expected authURL to be 'test', got %v", after)
}
}
func TestTokenUrl(t *testing.T) {
b := baseProvider{}
func TestTokenURL(t *testing.T) {
b := BaseProvider{}
before := b.TokenUrl()
before := b.TokenURL()
if before != "" {
t.Fatalf("Expected tokenUrl to be empty, got %v", before)
t.Fatalf("Expected tokenURL to be empty, got %v", before)
}
b.SetTokenUrl("test")
b.SetTokenURL("test")
after := b.TokenUrl()
after := b.TokenURL()
if after != "test" {
t.Fatalf("Expected tokenUrl to be 'test', got %v", after)
t.Fatalf("Expected tokenURL to be 'test', got %v", after)
}
}
func TestUserApiUrl(t *testing.T) {
b := baseProvider{}
func TestUserInfoURL(t *testing.T) {
b := BaseProvider{}
before := b.UserApiUrl()
before := b.UserInfoURL()
if before != "" {
t.Fatalf("Expected userApiUrl to be empty, got %v", before)
t.Fatalf("Expected userInfoURL to be empty, got %v", before)
}
b.SetUserApiUrl("test")
b.SetUserInfoURL("test")
after := b.UserApiUrl()
after := b.UserInfoURL()
if after != "test" {
t.Fatalf("Expected userApiUrl to be 'test', got %v", after)
t.Fatalf("Expected userInfoURL to be 'test', got %v", after)
}
}
func TestBuildAuthUrl(t *testing.T) {
b := baseProvider{
authUrl: "authUrl_test",
tokenUrl: "tokenUrl_test",
redirectUrl: "redirectUrl_test",
func TestBuildAuthURL(t *testing.T) {
b := BaseProvider{
authURL: "authURL_test",
tokenURL: "tokenURL_test",
redirectURL: "redirectURL_test",
clientId: "clientId_test",
clientSecret: "clientSecret_test",
scopes: []string{"test_scope"},
}
expected := "authUrl_test?access_type=offline&client_id=clientId_test&prompt=consent&redirect_uri=redirectUrl_test&response_type=code&scope=test_scope&state=state_test"
result := b.BuildAuthUrl("state_test", oauth2.AccessTypeOffline, oauth2.ApprovalForce)
expected := "authURL_test?access_type=offline&client_id=clientId_test&prompt=consent&redirect_uri=redirectURL_test&response_type=code&scope=test_scope&state=state_test"
result := b.BuildAuthURL("state_test", oauth2.AccessTypeOffline, oauth2.ApprovalForce)
if result != expected {
t.Errorf("Expected auth url %q, got %q", expected, result)
@@ -186,7 +186,7 @@ func TestBuildAuthUrl(t *testing.T) {
}
func TestClient(t *testing.T) {
b := baseProvider{}
b := BaseProvider{}
result := b.Client(&oauth2.Token{})
if result == nil {
@@ -195,10 +195,10 @@ func TestClient(t *testing.T) {
}
func TestOauth2Config(t *testing.T) {
b := baseProvider{
authUrl: "authUrl_test",
tokenUrl: "tokenUrl_test",
redirectUrl: "redirectUrl_test",
b := BaseProvider{
authURL: "authURL_test",
tokenURL: "tokenURL_test",
redirectURL: "redirectURL_test",
clientId: "clientId_test",
clientSecret: "clientSecret_test",
scopes: []string{"test"},
@@ -206,8 +206,8 @@ func TestOauth2Config(t *testing.T) {
result := b.oauth2Config()
if result.RedirectURL != b.RedirectUrl() {
t.Errorf("Expected redirectUrl %s, got %s", b.RedirectUrl(), result.RedirectURL)
if result.RedirectURL != b.RedirectURL() {
t.Errorf("Expected redirectURL %s, got %s", b.RedirectURL(), result.RedirectURL)
}
if result.ClientID != b.ClientId() {
@@ -218,12 +218,12 @@ func TestOauth2Config(t *testing.T) {
t.Errorf("Expected clientSecret %s, got %s", b.ClientSecret(), result.ClientSecret)
}
if result.Endpoint.AuthURL != b.AuthUrl() {
t.Errorf("Expected authUrl %s, got %s", b.AuthUrl(), result.Endpoint.AuthURL)
if result.Endpoint.AuthURL != b.AuthURL() {
t.Errorf("Expected authURL %s, got %s", b.AuthURL(), result.Endpoint.AuthURL)
}
if result.Endpoint.TokenURL != b.TokenUrl() {
t.Errorf("Expected authUrl %s, got %s", b.TokenUrl(), result.Endpoint.TokenURL)
if result.Endpoint.TokenURL != b.TokenURL() {
t.Errorf("Expected authURL %s, got %s", b.TokenURL(), result.Endpoint.TokenURL)
}
if len(result.Scopes) != len(b.Scopes()) || result.Scopes[0] != b.Scopes()[0] {
+12 -8
View File
@@ -10,6 +10,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameBitbucket] = wrapFactory(NewBitbucketProvider)
}
var _ Provider = (*Bitbucket)(nil)
// NameBitbucket is the unique name of the Bitbucket provider.
@@ -17,19 +21,19 @@ const NameBitbucket = "bitbucket"
// Bitbucket is an auth provider for Bitbucket.
type Bitbucket struct {
*baseProvider
BaseProvider
}
// NewBitbucketProvider creates a new Bitbucket provider instance with some defaults.
func NewBitbucketProvider() *Bitbucket {
return &Bitbucket{&baseProvider{
return &Bitbucket{BaseProvider{
ctx: context.Background(),
displayName: "Bitbucket",
pkce: false,
scopes: []string{"account"},
authUrl: "https://bitbucket.org/site/oauth2/authorize",
tokenUrl: "https://bitbucket.org/site/oauth2/access_token",
userApiUrl: "https://api.bitbucket.org/2.0/user",
authURL: "https://bitbucket.org/site/oauth2/authorize",
tokenURL: "https://bitbucket.org/site/oauth2/access_token",
userInfoURL: "https://api.bitbucket.org/2.0/user",
}}
}
@@ -37,7 +41,7 @@ func NewBitbucketProvider() *Bitbucket {
//
// API reference: https://developer.atlassian.com/cloud/bitbucket/rest/api-group-users/#api-user-get
func (p *Bitbucket) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -76,7 +80,7 @@ func (p *Bitbucket) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name: extracted.DisplayName,
Username: extracted.Username,
Email: email,
AvatarUrl: extracted.Links.Avatar.Href,
AvatarURL: extracted.Links.Avatar.Href,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
@@ -95,7 +99,7 @@ func (p *Bitbucket) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
//
// API reference: https://developer.atlassian.com/cloud/bitbucket/rest/api-group-users/#api-user-emails-get
func (p *Bitbucket) fetchPrimaryEmail(token *oauth2.Token) (string, error) {
response, err := p.Client(token).Get(p.userApiUrl + "/emails")
response, err := p.Client(token).Get(p.userInfoURL + "/emails")
if err != nil {
return "", err
}
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameDiscord] = wrapFactory(NewDiscordProvider)
}
var _ Provider = (*Discord)(nil)
// NameDiscord is the unique name of the Discord provider.
@@ -16,21 +20,21 @@ const NameDiscord string = "discord"
// Discord allows authentication via Discord OAuth2.
type Discord struct {
*baseProvider
BaseProvider
}
// NewDiscordProvider creates a new Discord provider instance with some defaults.
func NewDiscordProvider() *Discord {
// https://discord.com/developers/docs/topics/oauth2
// https://discord.com/developers/docs/resources/user#get-current-user
return &Discord{&baseProvider{
return &Discord{BaseProvider{
ctx: context.Background(),
displayName: "Discord",
pkce: true,
scopes: []string{"identify", "email"},
authUrl: "https://discord.com/api/oauth2/authorize",
tokenUrl: "https://discord.com/api/oauth2/token",
userApiUrl: "https://discord.com/api/users/@me",
authURL: "https://discord.com/api/oauth2/authorize",
tokenURL: "https://discord.com/api/oauth2/token",
userInfoURL: "https://discord.com/api/users/@me",
}}
}
@@ -38,7 +42,7 @@ func NewDiscordProvider() *Discord {
//
// API reference: https://discord.com/developers/docs/resources/user#user-object
func (p *Discord) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -62,7 +66,7 @@ func (p *Discord) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
// Build a full avatar URL using the avatar hash provided in the API response
// https://discord.com/developers/docs/reference#image-formatting
avatarUrl := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s.png", extracted.Id, extracted.Avatar)
avatarURL := fmt.Sprintf("https://cdn.discordapp.com/avatars/%s/%s.png", extracted.Id, extracted.Avatar)
// Concatenate the user's username and discriminator into a single username string
username := fmt.Sprintf("%s#%s", extracted.Username, extracted.Discriminator)
@@ -71,7 +75,7 @@ func (p *Discord) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: extracted.Id,
Name: username,
Username: extracted.Username,
AvatarUrl: avatarUrl,
AvatarURL: avatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+11 -7
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2/facebook"
)
func init() {
Providers[NameFacebook] = wrapFactory(NewFacebookProvider)
}
var _ Provider = (*Facebook)(nil)
// NameFacebook is the unique name of the Facebook provider.
@@ -16,19 +20,19 @@ const NameFacebook string = "facebook"
// Facebook allows authentication via Facebook OAuth2.
type Facebook struct {
*baseProvider
BaseProvider
}
// NewFacebookProvider creates new Facebook provider instance with some defaults.
func NewFacebookProvider() *Facebook {
return &Facebook{&baseProvider{
return &Facebook{BaseProvider{
ctx: context.Background(),
displayName: "Facebook",
pkce: true,
scopes: []string{"email"},
authUrl: facebook.Endpoint.AuthURL,
tokenUrl: facebook.Endpoint.TokenURL,
userApiUrl: "https://graph.facebook.com/me?fields=name,email,picture.type(large)",
authURL: facebook.Endpoint.AuthURL,
tokenURL: facebook.Endpoint.TokenURL,
userInfoURL: "https://graph.facebook.com/me?fields=name,email,picture.type(large)",
}}
}
@@ -36,7 +40,7 @@ func NewFacebookProvider() *Facebook {
//
// API reference: https://developers.facebook.com/docs/graph-api/reference/user/
func (p *Facebook) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -62,7 +66,7 @@ func (p *Facebook) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: extracted.Id,
Name: extracted.Name,
Email: extracted.Email,
AvatarUrl: extracted.Picture.Data.Url,
AvatarURL: extracted.Picture.Data.Url,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameGitea] = wrapFactory(NewGiteaProvider)
}
var _ Provider = (*Gitea)(nil)
// NameGitea is the unique name of the Gitea provider.
@@ -16,19 +20,19 @@ const NameGitea string = "gitea"
// Gitea allows authentication via Gitea OAuth2.
type Gitea struct {
*baseProvider
BaseProvider
}
// NewGiteaProvider creates new Gitea provider instance with some defaults.
func NewGiteaProvider() *Gitea {
return &Gitea{&baseProvider{
return &Gitea{BaseProvider{
ctx: context.Background(),
displayName: "Gitea",
pkce: true,
scopes: []string{"read:user", "user:email"},
authUrl: "https://gitea.com/login/oauth/authorize",
tokenUrl: "https://gitea.com/login/oauth/access_token",
userApiUrl: "https://gitea.com/api/v1/user",
authURL: "https://gitea.com/login/oauth/authorize",
tokenURL: "https://gitea.com/login/oauth/access_token",
userInfoURL: "https://gitea.com/api/v1/user",
}}
}
@@ -36,7 +40,7 @@ func NewGiteaProvider() *Gitea {
//
// API reference: https://try.gitea.io/api/swagger#/user/userGetCurrent
func (p *Gitea) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -51,7 +55,7 @@ func (p *Gitea) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name string `json:"full_name"`
Username string `json:"login"`
Email string `json:"email"`
AvatarUrl string `json:"avatar_url"`
AvatarURL string `json:"avatar_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -62,7 +66,7 @@ func (p *Gitea) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name: extracted.Name,
Username: extracted.Username,
Email: extracted.Email,
AvatarUrl: extracted.AvatarUrl,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -11,6 +11,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameGitee] = wrapFactory(NewGiteeProvider)
}
var _ Provider = (*Gitee)(nil)
// NameGitee is the unique name of the Gitee provider.
@@ -18,19 +22,19 @@ const NameGitee string = "gitee"
// Gitee allows authentication via Gitee OAuth2.
type Gitee struct {
*baseProvider
BaseProvider
}
// NewGiteeProvider creates new Gitee provider instance with some defaults.
func NewGiteeProvider() *Gitee {
return &Gitee{&baseProvider{
return &Gitee{BaseProvider{
ctx: context.Background(),
displayName: "Gitee",
pkce: true,
scopes: []string{"user_info", "emails"},
authUrl: "https://gitee.com/oauth/authorize",
tokenUrl: "https://gitee.com/oauth/token",
userApiUrl: "https://gitee.com/api/v5/user",
authURL: "https://gitee.com/oauth/authorize",
tokenURL: "https://gitee.com/oauth/token",
userInfoURL: "https://gitee.com/api/v5/user",
}}
}
@@ -38,7 +42,7 @@ func NewGiteeProvider() *Gitee {
//
// API reference: https://gitee.com/api/v5/swagger#/getV5User
func (p *Gitee) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -53,7 +57,7 @@ func (p *Gitee) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"avatar_url"`
AvatarURL string `json:"avatar_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -63,7 +67,7 @@ func (p *Gitee) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: strconv.Itoa(extracted.Id),
Name: extracted.Name,
Username: extracted.Login,
AvatarUrl: extracted.AvatarUrl,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+13 -9
View File
@@ -11,6 +11,10 @@ import (
"golang.org/x/oauth2/github"
)
func init() {
Providers[NameGithub] = wrapFactory(NewGithubProvider)
}
var _ Provider = (*Github)(nil)
// NameGithub is the unique name of the Github provider.
@@ -18,19 +22,19 @@ const NameGithub string = "github"
// Github allows authentication via Github OAuth2.
type Github struct {
*baseProvider
BaseProvider
}
// NewGithubProvider creates new Github provider instance with some defaults.
func NewGithubProvider() *Github {
return &Github{&baseProvider{
return &Github{BaseProvider{
ctx: context.Background(),
displayName: "GitHub",
pkce: true, // technically is not supported yet but it is safe as the PKCE params are just ignored
scopes: []string{"read:user", "user:email"},
authUrl: github.Endpoint.AuthURL,
tokenUrl: github.Endpoint.TokenURL,
userApiUrl: "https://api.github.com/user",
authURL: github.Endpoint.AuthURL,
tokenURL: github.Endpoint.TokenURL,
userInfoURL: "https://api.github.com/user",
}}
}
@@ -38,7 +42,7 @@ func NewGithubProvider() *Github {
//
// API reference: https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -53,7 +57,7 @@ func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"avatar_url"`
AvatarURL string `json:"avatar_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -64,7 +68,7 @@ func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name: extracted.Name,
Username: extracted.Login,
Email: extracted.Email,
AvatarUrl: extracted.AvatarUrl,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
@@ -95,7 +99,7 @@ func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
func (p *Github) fetchPrimaryEmail(token *oauth2.Token) (string, error) {
client := p.Client(token)
response, err := client.Get(p.userApiUrl + "/emails")
response, err := client.Get(p.userInfoURL + "/emails")
if err != nil {
return "", err
}
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameGitlab] = wrapFactory(NewGitlabProvider)
}
var _ Provider = (*Gitlab)(nil)
// NameGitlab is the unique name of the Gitlab provider.
@@ -16,19 +20,19 @@ const NameGitlab string = "gitlab"
// Gitlab allows authentication via Gitlab OAuth2.
type Gitlab struct {
*baseProvider
BaseProvider
}
// NewGitlabProvider creates new Gitlab provider instance with some defaults.
func NewGitlabProvider() *Gitlab {
return &Gitlab{&baseProvider{
return &Gitlab{BaseProvider{
ctx: context.Background(),
displayName: "GitLab",
pkce: true,
scopes: []string{"read_user"},
authUrl: "https://gitlab.com/oauth/authorize",
tokenUrl: "https://gitlab.com/oauth/token",
userApiUrl: "https://gitlab.com/api/v4/user",
authURL: "https://gitlab.com/oauth/authorize",
tokenURL: "https://gitlab.com/oauth/token",
userInfoURL: "https://gitlab.com/api/v4/user",
}}
}
@@ -36,7 +40,7 @@ func NewGitlabProvider() *Gitlab {
//
// API reference: https://docs.gitlab.com/ee/api/users.html#for-admin
func (p *Gitlab) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -51,7 +55,7 @@ func (p *Gitlab) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name string `json:"name"`
Username string `json:"username"`
Email string `json:"email"`
AvatarUrl string `json:"avatar_url"`
AvatarURL string `json:"avatar_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -62,7 +66,7 @@ func (p *Gitlab) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name: extracted.Name,
Username: extracted.Username,
Email: extracted.Email,
AvatarUrl: extracted.AvatarUrl,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+11 -7
View File
@@ -8,6 +8,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameGoogle] = wrapFactory(NewGoogleProvider)
}
var _ Provider = (*Google)(nil)
// NameGoogle is the unique name of the Google provider.
@@ -15,12 +19,12 @@ const NameGoogle string = "google"
// Google allows authentication via Google OAuth2.
type Google struct {
*baseProvider
BaseProvider
}
// NewGoogleProvider creates new Google provider instance with some defaults.
func NewGoogleProvider() *Google {
return &Google{&baseProvider{
return &Google{BaseProvider{
ctx: context.Background(),
displayName: "Google",
pkce: true,
@@ -28,15 +32,15 @@ func NewGoogleProvider() *Google {
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
},
authUrl: "https://accounts.google.com/o/oauth2/auth",
tokenUrl: "https://accounts.google.com/o/oauth2/token",
userApiUrl: "https://www.googleapis.com/oauth2/v1/userinfo",
authURL: "https://accounts.google.com/o/oauth2/auth",
tokenURL: "https://accounts.google.com/o/oauth2/token",
userInfoURL: "https://www.googleapis.com/oauth2/v1/userinfo",
}}
}
// FetchAuthUser returns an AuthUser instance based the Google's user api.
func (p *Google) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -60,7 +64,7 @@ func (p *Google) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Id: extracted.Id,
Name: extracted.Name,
AvatarUrl: extracted.Picture,
AvatarURL: extracted.Picture,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+10 -6
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2/instagram"
)
func init() {
Providers[NameInstagram] = wrapFactory(NewInstagramProvider)
}
var _ Provider = (*Instagram)(nil)
// NameInstagram is the unique name of the Instagram provider.
@@ -16,19 +20,19 @@ const NameInstagram string = "instagram"
// Instagram allows authentication via Instagram OAuth2.
type Instagram struct {
*baseProvider
BaseProvider
}
// NewInstagramProvider creates new Instagram provider instance with some defaults.
func NewInstagramProvider() *Instagram {
return &Instagram{&baseProvider{
return &Instagram{BaseProvider{
ctx: context.Background(),
displayName: "Instagram",
pkce: true,
scopes: []string{"user_profile"},
authUrl: instagram.Endpoint.AuthURL,
tokenUrl: instagram.Endpoint.TokenURL,
userApiUrl: "https://graph.instagram.com/me?fields=id,username,account_type",
authURL: instagram.Endpoint.AuthURL,
tokenURL: instagram.Endpoint.TokenURL,
userInfoURL: "https://graph.instagram.com/me?fields=id,username,account_type",
}}
}
@@ -36,7 +40,7 @@ func NewInstagramProvider() *Instagram {
//
// API reference: https://developers.facebook.com/docs/instagram-basic-display-api/reference/user#fields
func (p *Instagram) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
+12 -8
View File
@@ -10,6 +10,10 @@ import (
"golang.org/x/oauth2/kakao"
)
func init() {
Providers[NameKakao] = wrapFactory(NewKakaoProvider)
}
var _ Provider = (*Kakao)(nil)
// NameKakao is the unique name of the Kakao provider.
@@ -17,19 +21,19 @@ const NameKakao string = "kakao"
// Kakao allows authentication via Kakao OAuth2.
type Kakao struct {
*baseProvider
BaseProvider
}
// NewKakaoProvider creates a new Kakao provider instance with some defaults.
func NewKakaoProvider() *Kakao {
return &Kakao{&baseProvider{
return &Kakao{BaseProvider{
ctx: context.Background(),
displayName: "Kakao",
pkce: true,
scopes: []string{"account_email", "profile_nickname", "profile_image"},
authUrl: kakao.Endpoint.AuthURL,
tokenUrl: kakao.Endpoint.TokenURL,
userApiUrl: "https://kapi.kakao.com/v2/user/me",
authURL: kakao.Endpoint.AuthURL,
tokenURL: kakao.Endpoint.TokenURL,
userInfoURL: "https://kapi.kakao.com/v2/user/me",
}}
}
@@ -37,7 +41,7 @@ func NewKakaoProvider() *Kakao {
//
// API reference: https://developers.kakao.com/docs/latest/en/kakaologin/rest-api#req-user-info-response
func (p *Kakao) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -51,7 +55,7 @@ func (p *Kakao) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id int `json:"id"`
Profile struct {
Nickname string `json:"nickname"`
ImageUrl string `json:"profile_image"`
ImageURL string `json:"profile_image"`
} `json:"properties"`
KakaoAccount struct {
Email string `json:"email"`
@@ -66,7 +70,7 @@ func (p *Kakao) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Id: strconv.Itoa(extracted.Id),
Username: extracted.Profile.Nickname,
AvatarUrl: extracted.Profile.ImageUrl,
AvatarURL: extracted.Profile.ImageURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -8,6 +8,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameLivechat] = wrapFactory(NewLivechatProvider)
}
var _ Provider = (*Livechat)(nil)
// NameLivechat is the unique name of the Livechat provider.
@@ -15,19 +19,19 @@ const NameLivechat = "livechat"
// Livechat allows authentication via Livechat OAuth2.
type Livechat struct {
*baseProvider
BaseProvider
}
// NewLivechatProvider creates new Livechat provider instance with some defaults.
func NewLivechatProvider() *Livechat {
return &Livechat{&baseProvider{
return &Livechat{BaseProvider{
ctx: context.Background(),
displayName: "LiveChat",
pkce: true,
scopes: []string{}, // default scopes are specified from the provider dashboard
authUrl: "https://accounts.livechat.com/",
tokenUrl: "https://accounts.livechat.com/token",
userApiUrl: "https://accounts.livechat.com/v2/accounts/me",
authURL: "https://accounts.livechat.com/",
tokenURL: "https://accounts.livechat.com/token",
userInfoURL: "https://accounts.livechat.com/v2/accounts/me",
}}
}
@@ -35,7 +39,7 @@ func NewLivechatProvider() *Livechat {
//
// API reference: https://developers.livechat.com/docs/authorization
func (p *Livechat) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -50,7 +54,7 @@ func (p *Livechat) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name string `json:"name"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
AvatarUrl string `json:"avatar_url"`
AvatarURL string `json:"avatar_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -59,7 +63,7 @@ func (p *Livechat) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Id: extracted.Id,
Name: extracted.Name,
AvatarUrl: extracted.AvatarUrl,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+7 -3
View File
@@ -10,6 +10,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameMailcow] = wrapFactory(NewMailcowProvider)
}
var _ Provider = (*Mailcow)(nil)
// NameMailcow is the unique name of the mailcow provider.
@@ -17,12 +21,12 @@ const NameMailcow string = "mailcow"
// Mailcow allows authentication via mailcow OAuth2.
type Mailcow struct {
*baseProvider
BaseProvider
}
// NewMailcowProvider creates a new mailcow provider instance with some defaults.
func NewMailcowProvider() *Mailcow {
return &Mailcow{&baseProvider{
return &Mailcow{BaseProvider{
ctx: context.Background(),
displayName: "mailcow",
pkce: true,
@@ -34,7 +38,7 @@ func NewMailcowProvider() *Mailcow {
//
// API reference: https://github.com/mailcow/mailcow-dockerized/blob/master/data/web/oauth/profile.php
func (p *Mailcow) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
+10 -6
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2/microsoft"
)
func init() {
Providers[NameMicrosoft] = wrapFactory(NewMicrosoftProvider)
}
var _ Provider = (*Microsoft)(nil)
// NameMicrosoft is the unique name of the Microsoft provider.
@@ -16,20 +20,20 @@ const NameMicrosoft string = "microsoft"
// Microsoft allows authentication via AzureADEndpoint OAuth2.
type Microsoft struct {
*baseProvider
BaseProvider
}
// NewMicrosoftProvider creates new Microsoft AD provider instance with some defaults.
func NewMicrosoftProvider() *Microsoft {
endpoints := microsoft.AzureADEndpoint("")
return &Microsoft{&baseProvider{
return &Microsoft{BaseProvider{
ctx: context.Background(),
displayName: "Microsoft",
pkce: true,
scopes: []string{"User.Read"},
authUrl: endpoints.AuthURL,
tokenUrl: endpoints.TokenURL,
userApiUrl: "https://graph.microsoft.com/v1.0/me",
authURL: endpoints.AuthURL,
tokenURL: endpoints.TokenURL,
userInfoURL: "https://graph.microsoft.com/v1.0/me",
}}
}
@@ -38,7 +42,7 @@ func NewMicrosoftProvider() *Microsoft {
// API reference: https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
// Graph explorer: https://developer.microsoft.com/en-us/graph/graph-explorer
func (p *Microsoft) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
+12 -4
View File
@@ -8,6 +8,12 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameOIDC] = wrapFactory(NewOIDCProvider)
Providers[NameOIDC+"2"] = wrapFactory(NewOIDCProvider)
Providers[NameOIDC+"3"] = wrapFactory(NewOIDCProvider)
}
var _ Provider = (*OIDC)(nil)
// NameOIDC is the unique name of the OpenID Connect (OIDC) provider.
@@ -15,12 +21,12 @@ const NameOIDC string = "oidc"
// OIDC allows authentication via OpenID Connect (OIDC) OAuth2 provider.
type OIDC struct {
*baseProvider
BaseProvider
}
// NewOIDCProvider creates new OpenID Connect (OIDC) provider instance with some defaults.
func NewOIDCProvider() *OIDC {
return &OIDC{&baseProvider{
return &OIDC{BaseProvider{
ctx: context.Background(),
displayName: "OIDC",
pkce: true,
@@ -35,8 +41,10 @@ func NewOIDCProvider() *OIDC {
// FetchAuthUser returns an AuthUser instance based the provider's user api.
//
// API reference: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
//
// @todo consider adding support for reading the user data from the id_token.
func (p *OIDC) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -62,7 +70,7 @@ func (p *OIDC) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: extracted.Id,
Name: extracted.Name,
Username: extracted.Username,
AvatarUrl: extracted.Picture,
AvatarURL: extracted.Picture,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -8,6 +8,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NamePatreon] = wrapFactory(NewPatreonProvider)
}
var _ Provider = (*Patreon)(nil)
// NamePatreon is the unique name of the Patreon provider.
@@ -15,19 +19,19 @@ const NamePatreon string = "patreon"
// Patreon allows authentication via Patreon OAuth2.
type Patreon struct {
*baseProvider
BaseProvider
}
// NewPatreonProvider creates new Patreon provider instance with some defaults.
func NewPatreonProvider() *Patreon {
return &Patreon{&baseProvider{
return &Patreon{BaseProvider{
ctx: context.Background(),
displayName: "Patreon",
pkce: true,
scopes: []string{"identity", "identity[email]"},
authUrl: "https://www.patreon.com/oauth2/authorize",
tokenUrl: "https://www.patreon.com/api/oauth2/token",
userApiUrl: "https://www.patreon.com/api/oauth2/v2/identity?fields%5Buser%5D=full_name,email,vanity,image_url,is_email_verified",
authURL: "https://www.patreon.com/oauth2/authorize",
tokenURL: "https://www.patreon.com/api/oauth2/token",
userInfoURL: "https://www.patreon.com/api/oauth2/v2/identity?fields%5Buser%5D=full_name,email,vanity,image_url,is_email_verified",
}}
}
@@ -37,7 +41,7 @@ func NewPatreonProvider() *Patreon {
// https://docs.patreon.com/#get-api-oauth2-v2-identity
// https://docs.patreon.com/#user-v2
func (p *Patreon) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -54,7 +58,7 @@ func (p *Patreon) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Email string `json:"email"`
Name string `json:"full_name"`
Username string `json:"vanity"`
AvatarUrl string `json:"image_url"`
AvatarURL string `json:"image_url"`
IsEmailVerified bool `json:"is_email_verified"`
} `json:"attributes"`
} `json:"data"`
@@ -67,7 +71,7 @@ func (p *Patreon) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: extracted.Data.Id,
Username: extracted.Data.Attributes.Username,
Name: extracted.Data.Attributes.Name,
AvatarUrl: extracted.Data.Attributes.AvatarUrl,
AvatarURL: extracted.Data.Attributes.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NamePlanningcenter] = wrapFactory(NewPlanningcenterProvider)
}
var _ Provider = (*Planningcenter)(nil)
// NamePlanningcenter is the unique name of the Planningcenter provider.
@@ -16,19 +20,19 @@ const NamePlanningcenter string = "planningcenter"
// Planningcenter allows authentication via Planningcenter OAuth2.
type Planningcenter struct {
*baseProvider
BaseProvider
}
// NewPlanningcenterProvider creates a new Planningcenter provider instance with some defaults.
func NewPlanningcenterProvider() *Planningcenter {
return &Planningcenter{&baseProvider{
return &Planningcenter{BaseProvider{
ctx: context.Background(),
displayName: "Planning Center",
pkce: true,
scopes: []string{"people"},
authUrl: "https://api.planningcenteronline.com/oauth/authorize",
tokenUrl: "https://api.planningcenteronline.com/oauth/token",
userApiUrl: "https://api.planningcenteronline.com/people/v2/me",
authURL: "https://api.planningcenteronline.com/oauth/authorize",
tokenURL: "https://api.planningcenteronline.com/oauth/token",
userInfoURL: "https://api.planningcenteronline.com/people/v2/me",
}}
}
@@ -36,7 +40,7 @@ func NewPlanningcenterProvider() *Planningcenter {
//
// API reference: https://developer.planning.center/docs/#/overview/authentication
func (p *Planningcenter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -52,7 +56,7 @@ func (p *Planningcenter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Attributes struct {
Status string `json:"status"`
Name string `json:"name"`
AvatarUrl string `json:"avatar"`
AvatarURL string `json:"avatar"`
// don't map the email because users can have multiple assigned
// and it's not clear if they are verified
}
@@ -69,7 +73,7 @@ func (p *Planningcenter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Id: extracted.Data.Id,
Name: extracted.Data.Attributes.Name,
AvatarUrl: extracted.Data.Attributes.AvatarUrl,
AvatarURL: extracted.Data.Attributes.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2/spotify"
)
func init() {
Providers[NameSpotify] = wrapFactory(NewSpotifyProvider)
}
var _ Provider = (*Spotify)(nil)
// NameSpotify is the unique name of the Spotify provider.
@@ -16,12 +20,12 @@ const NameSpotify string = "spotify"
// Spotify allows authentication via Spotify OAuth2.
type Spotify struct {
*baseProvider
BaseProvider
}
// NewSpotifyProvider creates a new Spotify provider instance with some defaults.
func NewSpotifyProvider() *Spotify {
return &Spotify{&baseProvider{
return &Spotify{BaseProvider{
ctx: context.Background(),
displayName: "Spotify",
pkce: true,
@@ -30,9 +34,9 @@ func NewSpotifyProvider() *Spotify {
// currently Spotify doesn't return information whether the email is verified or not
// "user-read-email",
},
authUrl: spotify.Endpoint.AuthURL,
tokenUrl: spotify.Endpoint.TokenURL,
userApiUrl: "https://api.spotify.com/v1/me",
authURL: spotify.Endpoint.AuthURL,
tokenURL: spotify.Endpoint.TokenURL,
userInfoURL: "https://api.spotify.com/v1/me",
}}
}
@@ -40,7 +44,7 @@ func NewSpotifyProvider() *Spotify {
//
// API reference: https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
func (p *Spotify) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -54,7 +58,7 @@ func (p *Spotify) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id string `json:"id"`
Name string `json:"display_name"`
Images []struct {
Url string `json:"url"`
URL string `json:"url"`
} `json:"images"`
// don't map the email because per the official docs
// the email field is "unverified" and there is no proof
@@ -76,7 +80,7 @@ func (p *Spotify) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user.Expiry, _ = types.ParseDateTime(token.Expiry)
if len(extracted.Images) > 0 {
user.AvatarUrl = extracted.Images[0].Url
user.AvatarURL = extracted.Images[0].URL
}
return user, nil
+12 -8
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameStrava] = wrapFactory(NewStravaProvider)
}
var _ Provider = (*Strava)(nil)
// NameStrava is the unique name of the Strava provider.
@@ -16,21 +20,21 @@ const NameStrava string = "strava"
// Strava allows authentication via Strava OAuth2.
type Strava struct {
*baseProvider
BaseProvider
}
// NewStravaProvider creates new Strava provider instance with some defaults.
func NewStravaProvider() *Strava {
return &Strava{&baseProvider{
return &Strava{BaseProvider{
ctx: context.Background(),
displayName: "Strava",
pkce: true,
scopes: []string{
"profile:read_all",
},
authUrl: "https://www.strava.com/oauth/authorize",
tokenUrl: "https://www.strava.com/api/v3/oauth/token",
userApiUrl: "https://www.strava.com/api/v3/athlete",
authURL: "https://www.strava.com/oauth/authorize",
tokenURL: "https://www.strava.com/api/v3/oauth/token",
userInfoURL: "https://www.strava.com/api/v3/athlete",
}}
}
@@ -38,7 +42,7 @@ func NewStravaProvider() *Strava {
//
// API reference: https://developers.strava.com/docs/authentication/
func (p *Strava) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -53,7 +57,7 @@ func (p *Strava) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Username string `json:"username"`
ProfileImageUrl string `json:"profile"`
ProfileImageURL string `json:"profile"`
// At the time of writing, Strava OAuth2 doesn't support returning the user email address
// Email string `json:"email"`
@@ -65,7 +69,7 @@ func (p *Strava) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Name: extracted.FirstName + " " + extracted.LastName,
Username: extracted.Username,
AvatarUrl: extracted.ProfileImageUrl,
AvatarURL: extracted.ProfileImageURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+16 -12
View File
@@ -11,6 +11,10 @@ import (
"golang.org/x/oauth2/twitch"
)
func init() {
Providers[NameTwitch] = wrapFactory(NewTwitchProvider)
}
var _ Provider = (*Twitch)(nil)
// NameTwitch is the unique name of the Twitch provider.
@@ -18,19 +22,19 @@ const NameTwitch string = "twitch"
// Twitch allows authentication via Twitch OAuth2.
type Twitch struct {
*baseProvider
BaseProvider
}
// NewTwitchProvider creates new Twitch provider instance with some defaults.
func NewTwitchProvider() *Twitch {
return &Twitch{&baseProvider{
return &Twitch{BaseProvider{
ctx: context.Background(),
displayName: "Twitch",
pkce: true,
scopes: []string{"user:read:email"},
authUrl: twitch.Endpoint.AuthURL,
tokenUrl: twitch.Endpoint.TokenURL,
userApiUrl: "https://api.twitch.tv/helix/users",
authURL: twitch.Endpoint.AuthURL,
tokenURL: twitch.Endpoint.TokenURL,
userInfoURL: "https://api.twitch.tv/helix/users",
}}
}
@@ -38,7 +42,7 @@ func NewTwitchProvider() *Twitch {
//
// API reference: https://dev.twitch.tv/docs/api/reference#get-users
func (p *Twitch) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -54,7 +58,7 @@ func (p *Twitch) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Login string `json:"login"`
DisplayName string `json:"display_name"`
Email string `json:"email"`
ProfileImageUrl string `json:"profile_image_url"`
ProfileImageURL string `json:"profile_image_url"`
} `json:"data"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
@@ -70,7 +74,7 @@ func (p *Twitch) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Name: extracted.Data[0].DisplayName,
Username: extracted.Data[0].Login,
Email: extracted.Data[0].Email,
AvatarUrl: extracted.Data[0].ProfileImageUrl,
AvatarURL: extracted.Data[0].ProfileImageURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
@@ -81,16 +85,16 @@ func (p *Twitch) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
return user, nil
}
// FetchRawUserData implements Provider.FetchRawUserData interface.
// FetchRawUserInfo implements Provider.FetchRawUserInfo interface.
//
// This differ from baseProvider because Twitch requires the `Client-Id` header.
func (p *Twitch) FetchRawUserData(token *oauth2.Token) ([]byte, error) {
req, err := http.NewRequest("GET", p.userApiUrl, nil)
func (p *Twitch) FetchRawUserInfo(token *oauth2.Token) ([]byte, error) {
req, err := http.NewRequest("GET", p.userInfoURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("Client-Id", p.clientId)
return p.sendRawUserDataRequest(req, token)
return p.sendRawUserInfoRequest(req, token)
}
+12 -8
View File
@@ -8,6 +8,10 @@ import (
"golang.org/x/oauth2"
)
func init() {
Providers[NameTwitter] = wrapFactory(NewTwitterProvider)
}
var _ Provider = (*Twitter)(nil)
// NameTwitter is the unique name of the Twitter provider.
@@ -15,12 +19,12 @@ const NameTwitter string = "twitter"
// Twitter allows authentication via Twitter OAuth2.
type Twitter struct {
*baseProvider
BaseProvider
}
// NewTwitterProvider creates new Twitter provider instance with some defaults.
func NewTwitterProvider() *Twitter {
return &Twitter{&baseProvider{
return &Twitter{BaseProvider{
ctx: context.Background(),
displayName: "Twitter",
pkce: true,
@@ -31,9 +35,9 @@ func NewTwitterProvider() *Twitter {
// (see https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me)
"tweet.read",
},
authUrl: "https://twitter.com/i/oauth2/authorize",
tokenUrl: "https://api.twitter.com/2/oauth2/token",
userApiUrl: "https://api.twitter.com/2/users/me?user.fields=id,name,username,profile_image_url",
authURL: "https://twitter.com/i/oauth2/authorize",
tokenURL: "https://api.twitter.com/2/oauth2/token",
userInfoURL: "https://api.twitter.com/2/users/me?user.fields=id,name,username,profile_image_url",
}}
}
@@ -41,7 +45,7 @@ func NewTwitterProvider() *Twitter {
//
// API reference: https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me
func (p *Twitter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -56,7 +60,7 @@ func (p *Twitter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id string `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
ProfileImageUrl string `json:"profile_image_url"`
ProfileImageURL string `json:"profile_image_url"`
// NB! At the time of writing, Twitter OAuth2 doesn't support returning the user email address
// (see https://twittercommunity.com/t/which-api-to-get-user-after-oauth2-authorization/162417/33)
@@ -71,7 +75,7 @@ func (p *Twitter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: extracted.Data.Id,
Name: extracted.Data.Name,
Username: extracted.Data.Username,
AvatarUrl: extracted.Data.ProfileImageUrl,
AvatarURL: extracted.Data.ProfileImageURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+12 -8
View File
@@ -13,6 +13,10 @@ import (
"golang.org/x/oauth2/vk"
)
func init() {
Providers[NameVK] = wrapFactory(NewVKProvider)
}
var _ Provider = (*VK)(nil)
// NameVK is the unique name of the VK provider.
@@ -20,21 +24,21 @@ const NameVK string = "vk"
// VK allows authentication via VK OAuth2.
type VK struct {
*baseProvider
BaseProvider
}
// NewVKProvider creates new VK provider instance with some defaults.
//
// Docs: https://dev.vk.com/api/oauth-parameters
func NewVKProvider() *VK {
return &VK{&baseProvider{
return &VK{BaseProvider{
ctx: context.Background(),
displayName: "ВКонтакте",
pkce: false, // VK currently doesn't support PKCE and throws an error if PKCE params are send
scopes: []string{"email"},
authUrl: vk.Endpoint.AuthURL,
tokenUrl: vk.Endpoint.TokenURL,
userApiUrl: "https://api.vk.com/method/users.get?fields=photo_max,screen_name&v=5.131",
authURL: vk.Endpoint.AuthURL,
tokenURL: vk.Endpoint.TokenURL,
userInfoURL: "https://api.vk.com/method/users.get?fields=photo_max,screen_name&v=5.131",
}}
}
@@ -42,7 +46,7 @@ func NewVKProvider() *VK {
//
// API reference: https://dev.vk.com/method/users.get
func (p *VK) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -58,7 +62,7 @@ func (p *VK) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Username string `json:"screen_name"`
AvatarUrl string `json:"photo_max"`
AvatarURL string `json:"photo_max"`
} `json:"response"`
}{}
@@ -74,7 +78,7 @@ func (p *VK) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
Id: strconv.Itoa(extracted.Response[0].Id),
Name: strings.TrimSpace(extracted.Response[0].FirstName + " " + extracted.Response[0].LastName),
Username: extracted.Response[0].Username,
AvatarUrl: extracted.Response[0].AvatarUrl,
AvatarURL: extracted.Response[0].AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+11 -7
View File
@@ -9,6 +9,10 @@ import (
"golang.org/x/oauth2/yandex"
)
func init() {
Providers[NameYandex] = wrapFactory(NewYandexProvider)
}
var _ Provider = (*Yandex)(nil)
// NameYandex is the unique name of the Yandex provider.
@@ -16,21 +20,21 @@ const NameYandex string = "yandex"
// Yandex allows authentication via Yandex OAuth2.
type Yandex struct {
*baseProvider
BaseProvider
}
// NewYandexProvider creates new Yandex provider instance with some defaults.
//
// Docs: https://yandex.ru/dev/id/doc/en/
func NewYandexProvider() *Yandex {
return &Yandex{&baseProvider{
return &Yandex{BaseProvider{
ctx: context.Background(),
displayName: "Yandex",
pkce: true,
scopes: []string{"login:email", "login:avatar", "login:info"},
authUrl: yandex.Endpoint.AuthURL,
tokenUrl: yandex.Endpoint.TokenURL,
userApiUrl: "https://login.yandex.ru/info",
authURL: yandex.Endpoint.AuthURL,
tokenURL: yandex.Endpoint.TokenURL,
userInfoURL: "https://login.yandex.ru/info",
}}
}
@@ -38,7 +42,7 @@ func NewYandexProvider() *Yandex {
//
// API reference: https://yandex.ru/dev/id/doc/en/user-information#response-format
func (p *Yandex) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserData(token)
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
@@ -73,7 +77,7 @@ func (p *Yandex) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user.Expiry, _ = types.ParseDateTime(token.Expiry)
if !extracted.IsAvatarEmpty {
user.AvatarUrl = "https://avatars.yandex.net/get-yapic/" + extracted.AvatarId + "/islands-200"
user.AvatarURL = "https://avatars.yandex.net/get-yapic/" + extracted.AvatarId + "/islands-200"
}
return user, nil