From 257724301cb225944566e937f3b5bf8d19ac4d2b Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 17 Sep 2026 10:29:01 +0100 Subject: [PATCH] feat(ios): enhance Apple Sign In integration - Added support for custom nonce and requested scopes in Apple Sign In. - Introduced helper methods to configure Apple ID requests and map JavaScript scopes to iOS authorization scopes. - Improved handling of Apple Sign In parameters in the `preferImmediatelyAvailableCredentials` and `signUpWithApple` methods. --- ios/CredentialsManager.mm | 62 +++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/ios/CredentialsManager.mm b/ios/CredentialsManager.mm index 86f74f3..e3b05ce 100644 --- a/ios/CredentialsManager.mm +++ b/ios/CredentialsManager.mm @@ -3,6 +3,25 @@ #import #import +static NSArray *RNCMNSArrayFromLazyStringVector(const facebook::react::LazyVector &vec) +{ + NSMutableArray *result = [NSMutableArray arrayWithCapacity:vec.size()]; + for (size_t i = 0, n = vec.size(); i < n; i++) { + NSString *value = vec.at(i); + if (value != nil) { + [result addObject:value]; + } + } + return result; +} + +@interface CredentialsManager () +- (NSArray *)appleAuthorizationScopesFromJSScopes:(NSArray *)scopes; +- (void)configureAppleIDRequest:(ASAuthorizationAppleIDRequest *)request + nonce:(NSString *)nonce + requestedScopes:(NSArray *)requestedScopes; +@end + @implementation CredentialsManager RCT_EXPORT_MODULE() @@ -119,6 +138,14 @@ - (void)signIn:(NSArray *)options reject:(RCTPromiseRejectBlock)reject { id passkeyParams = params.passkeys(); + + NSString *appleNonce = nil; + NSArray *appleRequestedScopes = nil; + std::optional appleSignIn = params.appleSignIn(); + if (appleSignIn.has_value()) { + appleNonce = appleSignIn->nonce(); + appleRequestedScopes = RNCMNSArrayFromLazyStringVector(appleSignIn->requestedScopes()); + } dispatch_async(dispatch_get_main_queue(), ^{ self.currentResolve = resolve; @@ -169,9 +196,7 @@ - (void)signIn:(NSArray *)options } else if ([option isEqualToString:@"apple-signin"]) { ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init]; ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest]; - - NSArray *defaultScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail]; - appleIDRequest.requestedScopes = defaultScopes; + [self configureAppleIDRequest:appleIDRequest nonce:appleNonce requestedScopes:appleRequestedScopes]; [authRequests addObject:appleIDRequest]; } else if ([option isEqualToString:@"google-signin"]) { @@ -206,6 +231,8 @@ - (void)signUpWithGoogle:(JS::NativeCredentialsManager::GoogleSignInParams &)par - (void)signUpWithApple:(JS::NativeCredentialsManager::AppleSignInParams &)params resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + NSString *nonce = params.nonce(); + NSArray *requestedScopes = RNCMNSArrayFromLazyStringVector(params.requestedScopes()); dispatch_async(dispatch_get_main_queue(), ^{ self.currentResolve = resolve; @@ -213,8 +240,7 @@ - (void)signUpWithApple:(JS::NativeCredentialsManager::AppleSignInParams &)param ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init]; ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest]; - - appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail]; + [self configureAppleIDRequest:appleIDRequest nonce:nonce requestedScopes:requestedScopes]; ASAuthorizationController *authController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest]]; authController.delegate = self; @@ -378,6 +404,32 @@ - (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthoriz return keyWindow ?: [[UIApplication sharedApplication] windows].firstObject; } +#pragma mark - Apple Sign In Helpers + +- (NSArray *)appleAuthorizationScopesFromJSScopes:(NSArray *)scopes { + NSMutableArray *mappedScopes = [NSMutableArray array]; + for (NSString *scope in scopes) { + if ([scope isEqualToString:@"fullName"]) { + [mappedScopes addObject:ASAuthorizationScopeFullName]; + } else if ([scope isEqualToString:@"email"]) { + [mappedScopes addObject:ASAuthorizationScopeEmail]; + } + } + + return mappedScopes.count > 0 + ? [mappedScopes copy] + : @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail]; +} + +- (void)configureAppleIDRequest:(ASAuthorizationAppleIDRequest *)request + nonce:(NSString *)nonce + requestedScopes:(NSArray *)requestedScopes { + if (nonce.length > 0) { + request.nonce = nonce; + } + request.requestedScopes = [self appleAuthorizationScopesFromJSScopes:requestedScopes]; +} + #pragma mark - Helper Methods - (NSString *)createAuthenticationResponseJSON:(ASAuthorizationPlatformPublicKeyCredentialAssertion *)assertion {