diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be2fb63..acc2c0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ - Updated links formatting in the autogenerated html->text mail body. +- Added `expiry` field to the OAuth2 user response containing the _optional_ expiration time of the OAuth2 access token ([#3617](https://github.com/pocketbase/pocketbase/discussions/3617)). + ## v0.20.0-rc3 diff --git a/tools/auth/apple.go b/tools/auth/apple.go index 01b32b8c..49fd48dc 100644 --- a/tools/auth/apple.go +++ b/tools/auth/apple.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/golang-jwt/jwt/v4" + "github.com/pocketbase/pocketbase/tools/types" "github.com/spf13/cast" "golang.org/x/oauth2" ) @@ -74,6 +75,8 @@ func (p *Apple) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if cast.ToBool(extracted.EmailVerified) { user.Email = extracted.Email } diff --git a/tools/auth/auth.go b/tools/auth/auth.go index ae3982a3..d69b3493 100644 --- a/tools/auth/auth.go +++ b/tools/auth/auth.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -18,6 +19,7 @@ type AuthUser struct { RawUser map[string]any `json:"rawUser"` AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` + Expiry types.DateTime `json:"expiry"` } // Provider defines a common interface for an OAuth2 client. diff --git a/tools/auth/discord.go b/tools/auth/discord.go index a74dc76b..1fc86b7c 100644 --- a/tools/auth/discord.go +++ b/tools/auth/discord.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -73,6 +74,9 @@ func (p *Discord) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, } + + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.Verified { user.Email = extracted.Email } diff --git a/tools/auth/facebook.go b/tools/auth/facebook.go index c83acd39..fb16b059 100644 --- a/tools/auth/facebook.go +++ b/tools/auth/facebook.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/facebook" ) @@ -65,5 +66,7 @@ func (p *Facebook) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/gitea.go b/tools/auth/gitea.go index 8174f171..2643b184 100644 --- a/tools/auth/gitea.go +++ b/tools/auth/gitea.go @@ -5,6 +5,7 @@ import ( "encoding/json" "strconv" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -65,5 +66,7 @@ func (p *Gitea) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/gitee.go b/tools/auth/gitee.go index 5f314aa3..64362517 100644 --- a/tools/auth/gitee.go +++ b/tools/auth/gitee.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/go-ozzo/ozzo-validation/v4/is" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -66,6 +67,8 @@ func (p *Gitee) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.Email != "" && is.EmailFormat.Validate(extracted.Email) == nil { // valid public primary email user.Email = extracted.Email diff --git a/tools/auth/github.go b/tools/auth/github.go index af49aeff..b8c142a5 100644 --- a/tools/auth/github.go +++ b/tools/auth/github.go @@ -6,6 +6,7 @@ import ( "io" "strconv" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/github" ) @@ -67,6 +68,8 @@ func (p *Github) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + // in case user has set "Keep my email address private", send an // **optional** API request to retrieve the verified primary email if user.Email == "" { diff --git a/tools/auth/gitlab.go b/tools/auth/gitlab.go index cbf4f14d..c7a1931b 100644 --- a/tools/auth/gitlab.go +++ b/tools/auth/gitlab.go @@ -5,6 +5,7 @@ import ( "encoding/json" "strconv" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -65,5 +66,7 @@ func (p *Gitlab) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/google.go b/tools/auth/google.go index e42f7df1..c0ff7f7a 100644 --- a/tools/auth/google.go +++ b/tools/auth/google.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -63,6 +64,8 @@ func (p *Google) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.VerifiedEmail { user.Email = extracted.Email } diff --git a/tools/auth/instagram.go b/tools/auth/instagram.go index db2f60aa..a6ef9cf8 100644 --- a/tools/auth/instagram.go +++ b/tools/auth/instagram.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/instagram" ) @@ -59,5 +60,7 @@ func (p *Instagram) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/kakao.go b/tools/auth/kakao.go index 8c710970..b8455d4e 100644 --- a/tools/auth/kakao.go +++ b/tools/auth/kakao.go @@ -5,6 +5,7 @@ import ( "encoding/json" "strconv" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/kakao" ) @@ -68,6 +69,9 @@ func (p *Kakao) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, } + + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.KakaoAccount.IsEmailValid && extracted.KakaoAccount.IsEmailVerified { user.Email = extracted.KakaoAccount.Email } diff --git a/tools/auth/livechat.go b/tools/auth/livechat.go index f1972bd2..96e30136 100644 --- a/tools/auth/livechat.go +++ b/tools/auth/livechat.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -62,6 +63,8 @@ func (p *Livechat) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.EmailVerified { user.Email = extracted.Email } diff --git a/tools/auth/mailcow.go b/tools/auth/mailcow.go index cdd3c1ee..ee4f19c3 100644 --- a/tools/auth/mailcow.go +++ b/tools/auth/mailcow.go @@ -6,6 +6,7 @@ import ( "errors" "strings" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -66,6 +67,8 @@ func (p *Mailcow) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + // mailcow usernames are usually just the email adresses, so we just take the part in front of the @ if strings.Contains(user.Username, "@") { user.Username = strings.Split(user.Username, "@")[0] diff --git a/tools/auth/microsoft.go b/tools/auth/microsoft.go index 79083aa8..6152f04e 100644 --- a/tools/auth/microsoft.go +++ b/tools/auth/microsoft.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/microsoft" ) @@ -63,5 +64,7 @@ func (p *Microsoft) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/oidc.go b/tools/auth/oidc.go index 59d23dde..47c1bbfe 100644 --- a/tools/auth/oidc.go +++ b/tools/auth/oidc.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -65,6 +66,8 @@ func (p *OIDC) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.EmailVerified { user.Email = extracted.Email } diff --git a/tools/auth/patreon.go b/tools/auth/patreon.go index 90ccfb23..f06c6516 100644 --- a/tools/auth/patreon.go +++ b/tools/auth/patreon.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -70,6 +71,8 @@ func (p *Patreon) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.Data.Attributes.IsEmailVerified { user.Email = extracted.Data.Attributes.Email } diff --git a/tools/auth/spotify.go b/tools/auth/spotify.go index 3ca61076..6c30adf9 100644 --- a/tools/auth/spotify.go +++ b/tools/auth/spotify.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/spotify" ) @@ -69,6 +70,9 @@ func (p *Spotify) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, } + + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if len(extracted.Images) > 0 { user.AvatarUrl = extracted.Images[0].Url } diff --git a/tools/auth/strava.go b/tools/auth/strava.go index 2406edd0..e9f91c8e 100644 --- a/tools/auth/strava.go +++ b/tools/auth/strava.go @@ -5,6 +5,7 @@ import ( "encoding/json" "strconv" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -68,6 +69,8 @@ func (p *Strava) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if extracted.Id != 0 { user.Id = strconv.Itoa(extracted.Id) } diff --git a/tools/auth/twitch.go b/tools/auth/twitch.go index 1b9d590b..0d523ad6 100644 --- a/tools/auth/twitch.go +++ b/tools/auth/twitch.go @@ -6,6 +6,7 @@ import ( "errors" "net/http" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/twitch" ) @@ -73,6 +74,8 @@ func (p *Twitch) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/twitter.go b/tools/auth/twitter.go index a887b6c3..7fc11a30 100644 --- a/tools/auth/twitter.go +++ b/tools/auth/twitter.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" ) @@ -74,5 +75,7 @@ func (p *Twitter) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + return user, nil } diff --git a/tools/auth/vk.go b/tools/auth/vk.go index 936abe98..0446c5da 100644 --- a/tools/auth/vk.go +++ b/tools/auth/vk.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/vk" ) @@ -77,6 +78,8 @@ func (p *VK) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if email := token.Extra("email"); email != nil { user.Email = fmt.Sprint(email) } diff --git a/tools/auth/yandex.go b/tools/auth/yandex.go index 4befd8e5..8b03126a 100644 --- a/tools/auth/yandex.go +++ b/tools/auth/yandex.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" + "github.com/pocketbase/pocketbase/tools/types" "golang.org/x/oauth2" "golang.org/x/oauth2/yandex" ) @@ -67,6 +68,8 @@ func (p *Yandex) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) { RefreshToken: token.RefreshToken, } + user.Expiry, _ = types.ParseDateTime(token.Expiry) + if !extracted.IsAvatarEmpty { user.AvatarUrl = "https://avatars.yandex.net/get-yapic/" + extracted.AvatarId + "/islands-200" }