@@ -20,6 +20,14 @@ - (dispatch_queue_t)methodQueue
2020 return dispatch_get_main_queue ();
2121}
2222
23+ /* ! @brief Number of random bytes generated for the @ state.
24+ */
25+ static NSUInteger const kStateSizeBytes = 32 ;
26+
27+ /* ! @brief Number of random bytes generated for the @ codeVerifier.
28+ */
29+ static NSUInteger const kCodeVerifierBytes = 32 ;
30+
2331RCT_EXPORT_MODULE ()
2432
2533RCT_REMAP_METHOD(authorize,
@@ -28,6 +36,7 @@ - (dispatch_queue_t)methodQueue
2836 clientId: (NSString *) clientId
2937 clientSecret: (NSString *) clientSecret
3038 scopes: (NSArray *) scopes
39+ useNonce: (BOOL *) useNonce
3140 additionalParameters: (NSDictionary *_Nullable) additionalParameters
3241 serviceConfiguration: (NSDictionary *_Nullable) serviceConfiguration
3342 resolve: (RCTPromiseResolveBlock) resolve
@@ -41,6 +50,7 @@ - (dispatch_queue_t)methodQueue
4150 clientId: clientId
4251 clientSecret: clientSecret
4352 scopes: scopes
53+ useNonce: useNonce
4454 additionalParameters: additionalParameters
4555 resolve: resolve
4656 reject: reject];
@@ -56,6 +66,7 @@ - (dispatch_queue_t)methodQueue
5666 clientId: clientId
5767 clientSecret: clientSecret
5868 scopes: scopes
69+ useNonce: useNonce
5970 additionalParameters: additionalParameters
6071 resolve: resolve
6172 reject: reject];
@@ -126,6 +137,25 @@ - (OIDServiceConfiguration *) createServiceConfiguration: (NSDictionary *) servi
126137 return configuration;
127138}
128139
140+ + (nullable NSString *)generateCodeVerifier {
141+ return [OIDTokenUtilities randomURLSafeStringWithSize: kCodeVerifierBytes ];
142+ }
143+
144+ + (nullable NSString *)generateState {
145+ return [OIDTokenUtilities randomURLSafeStringWithSize: kStateSizeBytes ];
146+ }
147+
148+ + (nullable NSString *)codeChallengeS256ForVerifier : (NSString *)codeVerifier {
149+ if (!codeVerifier) {
150+ return nil ;
151+ }
152+ // generates the code_challenge per spec https://tools.ietf.org/html/rfc7636#section-4.2
153+ // code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
154+ // NB. the ASCII conversion on the code_verifier entropy was done at time of generation.
155+ NSData *sha256Verifier = [OIDTokenUtilities sha256: codeVerifier];
156+ return [OIDTokenUtilities encodeBase64urlNoPadding: sha256Verifier];
157+ }
158+
129159/*
130160 * Authorize a user in exchange for a token with provided OIDServiceConfiguration
131161 */
@@ -134,18 +164,29 @@ - (void)authorizeWithConfiguration: (OIDServiceConfiguration *) configuration
134164 clientId : (NSString *) clientId
135165 clientSecret : (NSString *) clientSecret
136166 scopes : (NSArray *) scopes
167+ useNonce : (BOOL *) useNonce
137168 additionalParameters : (NSDictionary *_Nullable) additionalParameters
138169 resolve : (RCTPromiseResolveBlock) resolve
139170 reject : (RCTPromiseRejectBlock) reject
140171{
172+
173+ NSString *codeVerifier = [[self class ] generateCodeVerifier ];
174+ NSString *codeChallenge = [[self class ] codeChallengeS256ForVerifier: codeVerifier];
175+ NSString *nonce = useNonce ? [[self class ] generateState ] : nil ;
176+
141177 // builds authentication request
142178 OIDAuthorizationRequest *request =
143179 [[OIDAuthorizationRequest alloc ] initWithConfiguration: configuration
144180 clientId: clientId
145181 clientSecret: clientSecret
146- scopes: scopes
182+ scope: [OIDScopeUtilities scopesWithArray: scopes]
147183 redirectURL: [NSURL URLWithString: redirectUrl]
148184 responseType: OIDResponseTypeCode
185+ state: [[self class ] generateState ]
186+ nonce: nonce
187+ codeVerifier: codeVerifier
188+ codeChallenge: codeChallenge
189+ codeChallengeMethod: OIDOAuthorizationRequestCodeChallengeMethodS256
149190 additionalParameters: additionalParameters];
150191
151192 // performs authentication request
@@ -163,7 +204,8 @@ - (void)authorizeWithConfiguration: (OIDServiceConfiguration *) configuration
163204 typeof (self) strongSelf = weakSelf;
164205 strongSelf->_currentSession = nil ;
165206 if (authState) {
166- resolve ([self formatResponse: authState.lastTokenResponse]);
207+ resolve ([self formatResponse: authState.lastTokenResponse
208+ withAdditionalParameters: authState.lastAuthorizationResponse.additionalParameters]);
167209 } else {
168210 reject (@" RNAppAuth Error" , [error localizedDescription ], error);
169211 }
@@ -225,4 +267,24 @@ - (NSDictionary*)formatResponse: (OIDTokenResponse*) response {
225267 };
226268}
227269
270+ /*
271+ * Take raw OIDTokenResponse and additional paramaeters from an OIDAuthorizationResponse
272+ * and turn them into an extended token response format to pass to JavaScript caller
273+ */
274+ - (NSDictionary *)formatResponse : (OIDTokenResponse*) response
275+ withAdditionalParameters : (NSDictionary *) params {
276+ NSDateFormatter *dateFormat = [[NSDateFormatter alloc ] init ];
277+ dateFormat.timeZone = [NSTimeZone timeZoneWithAbbreviation: @" UTC" ];
278+ [dateFormat setLocale: [NSLocale localeWithLocaleIdentifier: @" en_US_POSIX" ]];
279+ [dateFormat setDateFormat: @" yyyy-MM-dd'T'HH:mm:ss'Z'" ];
280+
281+ return @{@" accessToken" : response.accessToken ? response.accessToken : @" " ,
282+ @" accessTokenExpirationDate" : response.accessTokenExpirationDate ? [dateFormat stringFromDate: response.accessTokenExpirationDate] : @" " ,
283+ @" additionalParameters" : params,
284+ @" idToken" : response.idToken ? response.idToken : @" " ,
285+ @" refreshToken" : response.refreshToken ? response.refreshToken : @" " ,
286+ @" tokenType" : response.tokenType ? response.tokenType : @" " ,
287+ };
288+ }
289+
228290@end
0 commit comments