initial public commit
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// AuthUser defines a standardized oauth2 user data structure.
|
||||
type AuthUser struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
AvatarUrl string `json:"avatarUrl"`
|
||||
}
|
||||
|
||||
// Provider defines a common interface for an OAuth2 client.
|
||||
type Provider interface {
|
||||
// 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)
|
||||
|
||||
// ClientId 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)
|
||||
|
||||
// UserApiUrl returns the provider's user info api url.
|
||||
UserApiUrl() string
|
||||
|
||||
// SetUserApiUrl sets the provider's UserApiUrl.
|
||||
SetUserApiUrl(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
|
||||
// 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)
|
||||
|
||||
// FetchRawUserData requests and marshalizes into `result` the
|
||||
// the OAuth user api response.
|
||||
FetchRawUserData(token *oauth2.Token, result any) error
|
||||
|
||||
// FetchAuthUser is similar to FetchRawUserData, 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
|
||||
default:
|
||||
return nil, errors.New("Missing provider " + name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase/tools/auth"
|
||||
)
|
||||
|
||||
func TestNewProviderByName(t *testing.T) {
|
||||
var err error
|
||||
var p auth.Provider
|
||||
|
||||
// invalid
|
||||
p, err = auth.NewProviderByName("invalid")
|
||||
if err == nil {
|
||||
t.Error("Expected error, got nil")
|
||||
}
|
||||
if p != nil {
|
||||
t.Errorf("Expected provider to be nil, got %v", p)
|
||||
}
|
||||
|
||||
// google
|
||||
p, err = auth.NewProviderByName(auth.NameGoogle)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil, got error %v", err)
|
||||
}
|
||||
if _, ok := p.(*auth.Google); !ok {
|
||||
t.Error("Expected to be instance of *auth.Google")
|
||||
}
|
||||
|
||||
// facebook
|
||||
p, err = auth.NewProviderByName(auth.NameFacebook)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil, got error %v", err)
|
||||
}
|
||||
if _, ok := p.(*auth.Facebook); !ok {
|
||||
t.Error("Expected to be instance of *auth.Facebook")
|
||||
}
|
||||
|
||||
// github
|
||||
p, err = auth.NewProviderByName(auth.NameGithub)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil, got error %v", err)
|
||||
}
|
||||
if _, ok := p.(*auth.Github); !ok {
|
||||
t.Error("Expected to be instance of *auth.Github")
|
||||
}
|
||||
|
||||
// gitlab
|
||||
p, err = auth.NewProviderByName(auth.NameGitlab)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil, got error %v", err)
|
||||
}
|
||||
if _, ok := p.(*auth.Gitlab); !ok {
|
||||
t.Error("Expected to be instance of *auth.Gitlab")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// baseProvider defines common fields and methods used by OAuth2 client providers.
|
||||
type baseProvider struct {
|
||||
scopes []string
|
||||
clientId string
|
||||
clientSecret string
|
||||
redirectUrl string
|
||||
authUrl string
|
||||
tokenUrl string
|
||||
userApiUrl string
|
||||
}
|
||||
|
||||
// Scopes implements Provider.Scopes interface.
|
||||
func (p *baseProvider) Scopes() []string {
|
||||
return p.scopes
|
||||
}
|
||||
|
||||
// SetScopes implements Provider.SetScopes interface.
|
||||
func (p *baseProvider) SetScopes(scopes []string) {
|
||||
p.scopes = scopes
|
||||
}
|
||||
|
||||
// ClientId implements Provider.ClientId interface.
|
||||
func (p *baseProvider) ClientId() string {
|
||||
return p.clientId
|
||||
}
|
||||
|
||||
// SetClientId implements Provider.SetClientId interface.
|
||||
func (p *baseProvider) SetClientId(clientId string) {
|
||||
p.clientId = clientId
|
||||
}
|
||||
|
||||
// ClientSecret implements Provider.ClientSecret interface.
|
||||
func (p *baseProvider) ClientSecret() string {
|
||||
return p.clientSecret
|
||||
}
|
||||
|
||||
// SetClientSecret implements Provider.SetClientSecret interface.
|
||||
func (p *baseProvider) SetClientSecret(secret string) {
|
||||
p.clientSecret = secret
|
||||
}
|
||||
|
||||
// RedirectUrl implements Provider.RedirectUrl interface.
|
||||
func (p *baseProvider) RedirectUrl() string {
|
||||
return p.redirectUrl
|
||||
}
|
||||
|
||||
// SetRedirectUrl implements Provider.SetRedirectUrl interface.
|
||||
func (p *baseProvider) SetRedirectUrl(url string) {
|
||||
p.redirectUrl = url
|
||||
}
|
||||
|
||||
// AuthUrl implements Provider.AuthUrl interface.
|
||||
func (p *baseProvider) AuthUrl() string {
|
||||
return p.authUrl
|
||||
}
|
||||
|
||||
// SetAuthUrl implements Provider.SetAuthUrl interface.
|
||||
func (p *baseProvider) SetAuthUrl(url string) {
|
||||
p.authUrl = url
|
||||
}
|
||||
|
||||
// TokenUrl implements Provider.TokenUrl interface.
|
||||
func (p *baseProvider) TokenUrl() string {
|
||||
return p.tokenUrl
|
||||
}
|
||||
|
||||
// SetTokenUrl implements Provider.SetTokenUrl interface.
|
||||
func (p *baseProvider) SetTokenUrl(url string) {
|
||||
p.tokenUrl = url
|
||||
}
|
||||
|
||||
// UserApiUrl implements Provider.UserApiUrl interface.
|
||||
func (p *baseProvider) UserApiUrl() string {
|
||||
return p.userApiUrl
|
||||
}
|
||||
|
||||
// SetUserApiUrl implements Provider.SetUserApiUrl interface.
|
||||
func (p *baseProvider) SetUserApiUrl(url string) {
|
||||
p.userApiUrl = url
|
||||
}
|
||||
|
||||
// BuildAuthUrl implements Provider.BuildAuthUrl interface.
|
||||
func (p *baseProvider) BuildAuthUrl(state string, opts ...oauth2.AuthCodeOption) string {
|
||||
return p.oauth2Config().AuthCodeURL(state, opts...)
|
||||
}
|
||||
|
||||
// FetchToken implements Provider.FetchToken interface.
|
||||
func (p *baseProvider) FetchToken(code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error) {
|
||||
return p.oauth2Config().Exchange(context.Background(), code, opts...)
|
||||
}
|
||||
|
||||
// Client implements Provider.Client interface.
|
||||
func (p *baseProvider) Client(token *oauth2.Token) *http.Client {
|
||||
return p.oauth2Config().Client(context.Background(), token)
|
||||
}
|
||||
|
||||
// FetchRawUserData implements Provider.FetchRawUserData interface.
|
||||
func (p *baseProvider) FetchRawUserData(token *oauth2.Token, result any) error {
|
||||
client := p.Client(token)
|
||||
|
||||
response, err := client.Get(p.userApiUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return json.Unmarshal(content, &result)
|
||||
}
|
||||
|
||||
// oauth2Config constructs a oauth2.Config instance based on the provider settings.
|
||||
func (p *baseProvider) oauth2Config() *oauth2.Config {
|
||||
return &oauth2.Config{
|
||||
RedirectURL: p.redirectUrl,
|
||||
ClientID: p.clientId,
|
||||
ClientSecret: p.clientSecret,
|
||||
Scopes: p.scopes,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: p.authUrl,
|
||||
TokenURL: p.tokenUrl,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
func TestScopes(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.Scopes()
|
||||
if len(before) != 0 {
|
||||
t.Errorf("Expected 0 scopes, got %v", before)
|
||||
}
|
||||
|
||||
b.SetScopes([]string{"test1", "test2"})
|
||||
|
||||
after := b.Scopes()
|
||||
if len(after) != 2 {
|
||||
t.Errorf("Expected 2 scopes, got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientId(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.ClientId()
|
||||
if before != "" {
|
||||
t.Errorf("Expected clientId to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetClientId("test")
|
||||
|
||||
after := b.ClientId()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected clientId to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSecret(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.ClientSecret()
|
||||
if before != "" {
|
||||
t.Errorf("Expected clientSecret to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetClientSecret("test")
|
||||
|
||||
after := b.ClientSecret()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected clientSecret to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirectUrl(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.RedirectUrl()
|
||||
if before != "" {
|
||||
t.Errorf("Expected RedirectUrl to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetRedirectUrl("test")
|
||||
|
||||
after := b.RedirectUrl()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected RedirectUrl to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthUrl(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.AuthUrl()
|
||||
if before != "" {
|
||||
t.Errorf("Expected authUrl to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetAuthUrl("test")
|
||||
|
||||
after := b.AuthUrl()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected authUrl to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenUrl(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.TokenUrl()
|
||||
if before != "" {
|
||||
t.Errorf("Expected tokenUrl to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetTokenUrl("test")
|
||||
|
||||
after := b.TokenUrl()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected tokenUrl to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserApiUrl(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
before := b.UserApiUrl()
|
||||
if before != "" {
|
||||
t.Errorf("Expected userApiUrl to be empty, got %v", before)
|
||||
}
|
||||
|
||||
b.SetUserApiUrl("test")
|
||||
|
||||
after := b.UserApiUrl()
|
||||
if after != "test" {
|
||||
t.Errorf("Expected userApiUrl to be 'test', got %v", after)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("Expected auth url %q, got %q", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
b := baseProvider{}
|
||||
|
||||
result := b.Client(&oauth2.Token{})
|
||||
if result == nil {
|
||||
t.Error("Expected *http.Client instance, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOauth2Config(t *testing.T) {
|
||||
b := baseProvider{
|
||||
authUrl: "authUrl_test",
|
||||
tokenUrl: "tokenUrl_test",
|
||||
redirectUrl: "redirectUrl_test",
|
||||
clientId: "clientId_test",
|
||||
clientSecret: "clientSecret_test",
|
||||
scopes: []string{"test"},
|
||||
}
|
||||
|
||||
result := b.oauth2Config()
|
||||
|
||||
if result.RedirectURL != b.RedirectUrl() {
|
||||
t.Errorf("Expected redirectUrl %s, got %s", b.RedirectUrl(), result.RedirectURL)
|
||||
}
|
||||
|
||||
if result.ClientID != b.ClientId() {
|
||||
t.Errorf("Expected clientId %s, got %s", b.ClientId(), result.ClientID)
|
||||
}
|
||||
|
||||
if result.ClientSecret != b.ClientSecret() {
|
||||
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.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] {
|
||||
t.Errorf("Expected scopes %s, got %s", b.Scopes(), result.Scopes)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var _ Provider = (*Facebook)(nil)
|
||||
|
||||
// NameFacebook is the unique name of the Facebook provider.
|
||||
const NameFacebook string = "facebook"
|
||||
|
||||
// Facebook allows authentication via Facebook OAuth2.
|
||||
type Facebook struct {
|
||||
*baseProvider
|
||||
}
|
||||
|
||||
// NewFacebookProvider creates new Facebook provider instance with some defaults.
|
||||
func NewFacebookProvider() *Facebook {
|
||||
return &Facebook{&baseProvider{
|
||||
scopes: []string{"email"},
|
||||
authUrl: "https://www.facebook.com/dialog/oauth",
|
||||
tokenUrl: "https://graph.facebook.com/oauth/access_token",
|
||||
userApiUrl: "https://graph.facebook.com/me?fields=name,email,picture.type(large)",
|
||||
}}
|
||||
}
|
||||
|
||||
// FetchAuthUser returns an AuthUser instance based on the Facebook's user api.
|
||||
func (p *Facebook) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
|
||||
// https://developers.facebook.com/docs/graph-api/reference/user/
|
||||
rawData := struct {
|
||||
Id string
|
||||
Name string
|
||||
Email string
|
||||
Picture struct {
|
||||
Data struct{ Url string }
|
||||
}
|
||||
}{}
|
||||
|
||||
if err := p.FetchRawUserData(token, &rawData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &AuthUser{
|
||||
Id: rawData.Id,
|
||||
Name: rawData.Name,
|
||||
Email: rawData.Email,
|
||||
AvatarUrl: rawData.Picture.Data.Url,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var _ Provider = (*Github)(nil)
|
||||
|
||||
// NameGithub is the unique name of the Github provider.
|
||||
const NameGithub string = "github"
|
||||
|
||||
// Github allows authentication via Github OAuth2.
|
||||
type Github struct {
|
||||
*baseProvider
|
||||
}
|
||||
|
||||
// NewGithubProvider creates new Github provider instance with some defaults.
|
||||
func NewGithubProvider() *Github {
|
||||
return &Github{&baseProvider{
|
||||
scopes: []string{"user"},
|
||||
authUrl: "https://github.com/login/oauth/authorize",
|
||||
tokenUrl: "https://github.com/login/oauth/access_token",
|
||||
userApiUrl: "https://api.github.com/user",
|
||||
}}
|
||||
}
|
||||
|
||||
// FetchAuthUser returns an AuthUser instance based the Github's user api.
|
||||
func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
|
||||
// https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
|
||||
rawData := struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
}{}
|
||||
|
||||
if err := p.FetchRawUserData(token, &rawData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &AuthUser{
|
||||
Id: strconv.Itoa(rawData.Id),
|
||||
Name: rawData.Name,
|
||||
Email: rawData.Email,
|
||||
AvatarUrl: rawData.AvatarUrl,
|
||||
}
|
||||
|
||||
// in case user set "Keep my email address private",
|
||||
// email should be retrieved via extra API request
|
||||
if user.Email == "" {
|
||||
client := p.Client(token)
|
||||
|
||||
response, err := client.Get(p.userApiUrl + "/emails")
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
emails := []struct {
|
||||
Email string
|
||||
Verified bool
|
||||
Primary bool
|
||||
}{}
|
||||
if err := json.Unmarshal(content, &emails); err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
// extract the verified primary email
|
||||
for _, email := range emails {
|
||||
if email.Verified && email.Primary {
|
||||
user.Email = email.Email
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var _ Provider = (*Gitlab)(nil)
|
||||
|
||||
// NameGitlab is the unique name of the Gitlab provider.
|
||||
const NameGitlab string = "gitlab"
|
||||
|
||||
// Gitlab allows authentication via Gitlab OAuth2.
|
||||
type Gitlab struct {
|
||||
*baseProvider
|
||||
}
|
||||
|
||||
// NewGitlabProvider creates new Gitlab provider instance with some defaults.
|
||||
func NewGitlabProvider() *Gitlab {
|
||||
return &Gitlab{&baseProvider{
|
||||
scopes: []string{"read_user"},
|
||||
authUrl: "https://gitlab.com/oauth/authorize",
|
||||
tokenUrl: "https://gitlab.com/oauth/token",
|
||||
userApiUrl: "https://gitlab.com/api/v4/user",
|
||||
}}
|
||||
}
|
||||
|
||||
// FetchAuthUser returns an AuthUser instance based the Gitlab's user api.
|
||||
func (p *Gitlab) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
|
||||
// https://docs.gitlab.com/ee/api/users.html#for-admin
|
||||
rawData := struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
}{}
|
||||
|
||||
if err := p.FetchRawUserData(token, &rawData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &AuthUser{
|
||||
Id: strconv.Itoa(rawData.Id),
|
||||
Name: rawData.Name,
|
||||
Email: rawData.Email,
|
||||
AvatarUrl: rawData.AvatarUrl,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var _ Provider = (*Google)(nil)
|
||||
|
||||
// NameGoogle is the unique name of the Google provider.
|
||||
const NameGoogle string = "google"
|
||||
|
||||
// Google allows authentication via Google OAuth2.
|
||||
type Google struct {
|
||||
*baseProvider
|
||||
}
|
||||
|
||||
// NewGoogleProvider creates new Google provider instance with some defaults.
|
||||
func NewGoogleProvider() *Google {
|
||||
return &Google{&baseProvider{
|
||||
scopes: []string{
|
||||
"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",
|
||||
}}
|
||||
}
|
||||
|
||||
// FetchAuthUser returns an AuthUser instance based the Google's user api.
|
||||
func (p *Google) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
|
||||
// https://cloud.google.com/identity-platform/docs/reference/rest/v1/UserInfo
|
||||
rawData := struct {
|
||||
LocalId string `json:"localId"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Email string `json:"email"`
|
||||
PhotoUrl string `json:"photoUrl"`
|
||||
}{}
|
||||
|
||||
if err := p.FetchRawUserData(token, &rawData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &AuthUser{
|
||||
Id: rawData.LocalId,
|
||||
Name: rawData.DisplayName,
|
||||
Email: rawData.Email,
|
||||
AvatarUrl: rawData.PhotoUrl,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
Reference in New Issue
Block a user