diff --git a/providers/apple/apple.go b/providers/apple/apple.go index cd3926b7..b53a1e69 100644 --- a/providers/apple/apple.go +++ b/providers/apple/apple.go @@ -121,13 +121,12 @@ func (Provider) UnmarshalSession(data string) (goth.Session, error) { return s, err } -// Apple doesn't seem to provide a user profile endpoint like all the other providers do. -// Therefore this will return a User with the unique identifier obtained through authorization -// as the only identifying attribute. // A full name and email can be obtained from the form post response (parameter 'user') // to the redirect page following authentication, if the name and email scopes are requested. // Additionally, if the response type is form_post and the email scope is requested, the email // will be encoded into the ID token in the email claim. +// Note that the full name is only provided on the very first authentication of a user, and +// subsequent authentications will not include the full name, even if requested. func (p Provider) FetchUser(session goth.Session) (goth.User, error) { s := session.(*Session) if s.AccessToken == "" { @@ -140,6 +139,8 @@ func (p Provider) FetchUser(session goth.Session) (goth.User, error) { AccessToken: s.AccessToken, RefreshToken: s.RefreshToken, ExpiresAt: s.ExpiresAt, + FirstName: s.FirstName, + LastName: s.LastName, }, nil } diff --git a/providers/apple/apple_test.go b/providers/apple/apple_test.go index 2b5021f3..f76a294a 100644 --- a/providers/apple/apple_test.go +++ b/providers/apple/apple_test.go @@ -93,6 +93,7 @@ func TestAuthorize(t *testing.T) { _, err := session.Authorize(p, url.Values{ "code": []string{""}, + "user": []string{"{\"first_name\":\"John\",\"last_name\":\"Doe\"}"}, }) if err != nil { errStr := err.Error() diff --git a/providers/apple/session.go b/providers/apple/session.go index becfef36..5ce7b4d0 100644 --- a/providers/apple/session.go +++ b/providers/apple/session.go @@ -32,6 +32,8 @@ type Session struct { AccessToken string RefreshToken string ExpiresAt time.Time + FirstName string + LastName string ID } @@ -119,6 +121,21 @@ func (s *Session) Authorize(provider goth.Provider, params goth.Params) (string, IsPrivateEmail: idToken.Claims.(*IDTokenClaims).IsPrivateEmail.Value(), EmailVerified: idToken.Claims.(*IDTokenClaims).EmailVerified.Value(), } + + // fetch the user first and last name from the params if available. + if user := params.Get("user"); user != "" { + var userData struct { + Name struct { + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + } `json:"name"` + Email string `json:"email"` + } + if err := json.Unmarshal([]byte(user), &userData); err == nil { + s.FirstName = userData.Name.FirstName + s.LastName = userData.Name.LastName + } + } } return token.AccessToken, err diff --git a/providers/apple/session_test.go b/providers/apple/session_test.go index 031b9163..ef8ed1b4 100644 --- a/providers/apple/session_test.go +++ b/providers/apple/session_test.go @@ -37,7 +37,7 @@ func Test_ToJSON(t *testing.T) { s := &Session{} data := s.Marshal() - a.Equal(data, `{"AuthURL":"","AccessToken":"","RefreshToken":"","ExpiresAt":"0001-01-01T00:00:00Z","sub":"","email":"","is_private_email":false,"email_verified":false}`) + a.Equal(data, `{"AuthURL":"","AccessToken":"","RefreshToken":"","ExpiresAt":"0001-01-01T00:00:00Z","FirstName":"","LastName":"","sub":"","email":"","is_private_email":false,"email_verified":false}`) } func Test_String(t *testing.T) {