Skip to content

Commit 91da16a

Browse files
authored
Merge pull request #996 from firebase/rosalyntan.nonce
Attach a nonce to Sign in with Apple requests.
2 parents 7fc24d8 + fa3602e commit 91da16a

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

FirebaseAuthUI/FirebaseAuthUITests/FUIAuthTest.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,13 @@ - (void)testUseEmulatorSetsFIRAuthEmulator {
152152
OCMVerify([mockAuth useEmulatorWithHost:@"host" port:12345]);
153153
}
154154

155+
- (void)testStringBySHA256HashingString {
156+
NSString *inputString = @"abc-123.ZYX_987";
157+
NSString *expectedSHA256HashedString = @"d858d78754a50c8ccdc414946f656fe854e6ba76bf09a79a7e7d9ca135e4b58d";
158+
159+
NSString *actualSHA256HashedString = [FUIAuthUtils stringBySHA256HashingString:inputString];
160+
161+
XCTAssertEqualObjects(actualSHA256HashedString, expectedSHA256HashedString);
162+
}
163+
155164
@end

FirebaseAuthUI/Sources/FUIAuthUtils.m

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#import "FirebaseAuthUI/Sources/Public/FirebaseAuthUI/FUIAuthUtils.h"
1818

19+
#import <CommonCrypto/CommonCrypto.h>
20+
1921
#if SWIFT_PACKAGE
2022
NSString *const FUIAuthBundleName = @"FirebaseUI_FirebaseAuthUI";
2123
#else
@@ -74,4 +76,51 @@ + (nullable UIImage *)imageNamed:(NSString *)name fromBundle:(nullable NSBundle
7476
}
7577
}
7678

79+
+ (NSString *)randomNonce {
80+
// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
81+
NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
82+
NSMutableString *result = [NSMutableString string];
83+
NSInteger remainingLength = 32;
84+
85+
while (remainingLength > 0) {
86+
NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
87+
for (NSInteger i = 0; i < 16; i++) {
88+
uint8_t random = 0;
89+
int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
90+
if (errorCode != errSecSuccess) {
91+
[NSException raise:@"FUIAuthGenerateRandomNonce"
92+
format:@"Unable to generate nonce: OSStatus %i", errorCode];
93+
}
94+
95+
[randoms addObject:@(random)];
96+
}
97+
98+
for (NSNumber *random in randoms) {
99+
if (remainingLength == 0) {
100+
break;
101+
}
102+
103+
if (random.unsignedIntValue < characterSet.length) {
104+
unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
105+
[result appendFormat:@"%C", character];
106+
remainingLength--;
107+
}
108+
}
109+
}
110+
111+
return result;
112+
}
113+
114+
+ (NSString *)stringBySHA256HashingString:(NSString *)input {
115+
const char *string = [input UTF8String];
116+
unsigned char result[CC_SHA256_DIGEST_LENGTH];
117+
CC_SHA256(string, (CC_LONG)strlen(string), result);
118+
119+
NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
120+
for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
121+
[hashed appendFormat:@"%02x", result[i]];
122+
}
123+
return hashed;
124+
}
125+
77126
@end

FirebaseAuthUI/Sources/Public/FirebaseAuthUI/FUIAuthUtils.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ extern NSString *const FUIAuthBundleName;
4747
*/
4848
+ (nullable UIImage *)imageNamed:(NSString *)name fromBundle:(nullable NSBundle *)bundle;
4949

50+
/** @fn randomNonce
51+
@brief Generates a random 32-character nonce.
52+
*/
53+
+ (NSString *)randomNonce;
54+
55+
/** @fn stringBySHA256HashingString:
56+
@brief Generates the SHA-256 hash of the input string.
57+
@param input The input string to be hashed.
58+
*/
59+
+ (NSString *)stringBySHA256HashingString:(NSString *)input;
60+
5061
@end
5162

5263
NS_ASSUME_NONNULL_END

FirebaseOAuthUI/Sources/FUIOAuth.m

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ @interface FUIOAuth () <ASAuthorizationControllerDelegate, ASAuthorizationContro
9999
*/
100100
@property(nonatomic, copy, nullable) NSString *loginHintKey;
101101

102+
@property(nonatomic, copy, nullable) NSString *currentNonce;
103+
102104
/** @property provider
103105
@brief The OAuth provider that does the actual sign in.
104106
*/
@@ -292,8 +294,11 @@ - (void)signInWithDefaultValue:(nullable NSString *)defaultValue
292294

293295
if ([self.providerID isEqualToString:@"apple.com"] && !self.authUI.isEmulatorEnabled) {
294296
if (@available(iOS 13.0, *)) {
297+
NSString *nonce = [FUIAuthUtils randomNonce];
298+
self.currentNonce = nonce;
295299
ASAuthorizationAppleIDRequest *request = [[[ASAuthorizationAppleIDProvider alloc] init] createRequest];
296300
request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
301+
request.nonce = [FUIAuthUtils stringBySHA256HashingString:nonce];
297302
ASAuthorizationController* controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
298303
controller.delegate = self;
299304
controller.presentationContextProvider = self;
@@ -368,9 +373,10 @@ - (void)authorizationController:(ASAuthorizationController *)controller didCompl
368373
_providerSignInCompletion(nil, nil, nil, nil);
369374
}
370375
NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken encoding:NSUTF8StringEncoding];
376+
NSString *rawNonce = self.currentNonce;
371377
FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
372378
IDToken:idToken
373-
accessToken:nil];
379+
rawNonce:rawNonce];
374380
FIRAuthResultCallback result;
375381
NSPersonNameComponents *nameComponents = appleIDCredential.fullName;
376382
if (nameComponents != nil) {

0 commit comments

Comments
 (0)