I have implemented basic Sign in with Apple functionality to my app. When the app is launched, the user will be presented with a Continue with Apple view, where they can authenticate. Once signed in, they will return to a view that reads "Hello, [User's Name]". However, I cannot seem to figure out why the email and name return nil after authentication. For example, when authentication is successful, the HelloView simply reads "Hello, " with no name. I have it setup so that the users name and email are saved to AppStorage variables, and then inserted into a Profile class with SwiftData.
import AuthenticationServices
import SwiftData
import SwiftUI
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
@Environment(\.modelContext) var modelContext
@AppStorage("email") var email: String = ""
@AppStorage("firstName") var firstName: String = ""
@AppStorage("lastName") var lastName: String = ""
@AppStorage("userID") var userID: String = ""
@Query var userProfile: [Profile]
private var isSignedIn: Bool {
!userID.isEmpty
}
var body: some View {
VStack {
if !isSignedIn {
SignInView()
} else {
HomeView()
}
}
}
}
struct SignInView: View {
@Environment(\.colorScheme) var colorScheme
@Environment(\.modelContext) var modelContext
@AppStorage("email") var email: String = ""
@AppStorage("firstName") var firstName: String = ""
@AppStorage("lastName") var lastName: String = ""
@AppStorage("userID") var userID: String = ""
@Query var userProfile: [Profile]
var body: some View {
NavigationStack {
Spacer()
SignInWithAppleButton(.continue) { request in
request.requestedScopes = [.email, .fullName]
} onCompletion: { result in
switch result {
case .success(let auth):
switch auth.credential {
case let credential as ASAuthorizationAppleIDCredential:
// User ID
let userID = credential.user
// User Info
let email = credential.email
print(email!)
let firstName = credential.fullName?.givenName
print(firstName!)
let lastName = credential.fullName?.familyName
print(lastName!)
self.email = email ?? ""
self.userID = userID
self.firstName = firstName ?? ""
self.lastName = lastName ?? ""
createProfile()
default:
break
}
case .failure(let error):
print("Error signing in with Apple: \(error.localizedDescription)")
}
}
.signInWithAppleButtonStyle(colorScheme == .dark ? .white : .black)
.frame(height: 50)
.padding()
.cornerRadius(12)
.navigationTitle("[App Name]")
}
}
func createProfile() {
let newProfile = Profile(firstName: firstName, lastName: lastName, email: email, userID: userID)
modelContext.insert(newProfile)
}
}
This is how I have my HomeView setup:
import SwiftData
import SwiftUI
struct HomeView: View {
@Environment(\.modelContext) var modelContext
@Query var user: [Profile]
var body: some View {
ForEach(user) { user in
Text("Hello, \(user.firstName)")
}
}
}
#Preview {
HomeView()
}
And here's the Profile class:
import Foundation
import SwiftData
@Model
class Profile {
var firstName: String
var lastName: String
var email: String
var userID: String
init(firstName: String, lastName: String, email: String, userID: String) {
self.firstName = firstName
self.lastName = lastName
self.email = email
self.userID = userID
}
}
Hi @Carter58,
The user's first and last name are not provided to Apple—they are passed directly to the client in the initial authorization response and not included in the identity token in subsequent responses. Please see the documentation below for more information:
Send information to app servers and verify tokens
Ensure that your app relays the credentials and user information to your app servers. The API collects this information and shares it with your app the first time the user logs in using Sign in with Apple. If the user then uses Sign in with Apple on another device, the API doesn’t ask for the user’s name or email again. It collects the information again only if the user stops using Sign in with Apple and later reconnects to your app.
Although Apple provides the user’s email address in the identity token on all subsequent API responses, it doesn’t include other information about the user, such as their name. When you receive user information from the API response, immediately store it locally so your app can access it again in the event of a process or network failure.
Authenticating users with Sign in with Apple https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple#3383773
Cheers,
Paris X Pinkney | WWDR | DTS Engineer