2424
2525import com .rnappauth .utils .MapUtil ;
2626import com .rnappauth .utils .UnsafeConnectionBuilder ;
27+ import com .rnappauth .utils .RegistrationResponseFactory ;
2728import com .rnappauth .utils .TokenResponseFactory ;
2829import com .rnappauth .utils .CustomConnectionBuilder ;
2930
3637import net .openid .appauth .ClientAuthentication ;
3738import net .openid .appauth .ClientSecretBasic ;
3839import net .openid .appauth .ClientSecretPost ;
40+ import net .openid .appauth .RegistrationRequest ;
41+ import net .openid .appauth .RegistrationResponse ;
3942import net .openid .appauth .ResponseTypeValues ;
4043import net .openid .appauth .TokenResponse ;
4144import net .openid .appauth .TokenRequest ;
4245import net .openid .appauth .connectivity .ConnectionBuilder ;
4346import net .openid .appauth .connectivity .DefaultConnectionBuilder ;
4447
48+ import java .util .ArrayList ;
4549import java .util .Collections ;
4650import java .util .HashMap ;
51+ import java .util .List ;
4752import java .util .Map ;
4853import java .util .concurrent .atomic .AtomicReference ;
4954import java .util .concurrent .CountDownLatch ;
@@ -56,6 +61,7 @@ public class RNAppAuthModule extends ReactContextBaseJavaModule implements Activ
5661 private Promise promise ;
5762 private Boolean dangerouslyAllowInsecureHttpRequests ;
5863 private String clientAuthMethod = "basic" ;
64+ private Map <String , String > registrationRequestHeaders = null ;
5965 private Map <String , String > authorizationRequestHeaders = null ;
6066 private Map <String , String > tokenRequestHeaders = null ;
6167 private Map <String , String > additionalParametersMap ;
@@ -130,6 +136,75 @@ public void onFetchConfigurationCompleted(
130136 }
131137 }
132138
139+ @ ReactMethod
140+ public void register (
141+ String issuer ,
142+ final ReadableArray redirectUris ,
143+ final ReadableArray responseTypes ,
144+ final ReadableArray grantTypes ,
145+ final String subjectType ,
146+ final String tokenEndpointAuthMethod ,
147+ final ReadableMap additionalParameters ,
148+ final ReadableMap serviceConfiguration ,
149+ final Boolean dangerouslyAllowInsecureHttpRequests ,
150+ final ReadableMap headers ,
151+ final Promise promise
152+ ) {
153+ this .parseHeaderMap (headers );
154+ final ConnectionBuilder builder = createConnectionBuilder (dangerouslyAllowInsecureHttpRequests , this .registrationRequestHeaders );
155+ final AppAuthConfiguration appAuthConfiguration = this .createAppAuthConfiguration (builder );
156+ final HashMap <String , String > additionalParametersMap = MapUtil .readableMapToHashMap (additionalParameters );
157+
158+ // when serviceConfiguration is provided, we don't need to hit up the OpenID well-known id endpoint
159+ if (serviceConfiguration != null || mServiceConfiguration .get () != null ) {
160+ try {
161+ final AuthorizationServiceConfiguration serviceConfig = mServiceConfiguration .get () != null ? mServiceConfiguration .get () : createAuthorizationServiceConfiguration (serviceConfiguration );
162+ registerWithConfiguration (
163+ serviceConfig ,
164+ appAuthConfiguration ,
165+ redirectUris ,
166+ responseTypes ,
167+ grantTypes ,
168+ subjectType ,
169+ tokenEndpointAuthMethod ,
170+ additionalParametersMap ,
171+ promise
172+ );
173+ } catch (Exception e ) {
174+ promise .reject ("Failed to refresh token" , e .getMessage ());
175+ }
176+ } else {
177+ final Uri issuerUri = Uri .parse (issuer );
178+ AuthorizationServiceConfiguration .fetchFromUrl (
179+ buildConfigurationUriFromIssuer (issuerUri ),
180+ new AuthorizationServiceConfiguration .RetrieveConfigurationCallback () {
181+ public void onFetchConfigurationCompleted (
182+ @ Nullable AuthorizationServiceConfiguration fetchedConfiguration ,
183+ @ Nullable AuthorizationException ex ) {
184+ if (ex != null ) {
185+ promise .reject ("Failed to fetch configuration" , getErrorMessage (ex ));
186+ return ;
187+ }
188+
189+ mServiceConfiguration .set (fetchedConfiguration );
190+
191+ registerWithConfiguration (
192+ fetchedConfiguration ,
193+ appAuthConfiguration ,
194+ redirectUris ,
195+ responseTypes ,
196+ grantTypes ,
197+ subjectType ,
198+ tokenEndpointAuthMethod ,
199+ additionalParametersMap ,
200+ promise
201+ );
202+ }
203+ },
204+ builder );
205+ }
206+ }
207+
133208 @ ReactMethod
134209 public void authorize (
135210 String issuer ,
@@ -150,10 +225,6 @@ public void authorize(
150225 final AppAuthConfiguration appAuthConfiguration = this .createAppAuthConfiguration (builder );
151226 final HashMap <String , String > additionalParametersMap = MapUtil .readableMapToHashMap (additionalParameters );
152227
153- if (clientSecret != null ) {
154- additionalParametersMap .put ("client_secret" , clientSecret );
155- }
156-
157228 // store args in private fields for later use in onActivityResult handler
158229 this .promise = promise ;
159230 this .dangerouslyAllowInsecureHttpRequests = dangerouslyAllowInsecureHttpRequests ;
@@ -345,6 +416,64 @@ public void onTokenRequestCompleted(
345416 }
346417 }
347418
419+ /*
420+ * Perform dynamic client registration with the provided configuration
421+ */
422+ private void registerWithConfiguration (
423+ final AuthorizationServiceConfiguration serviceConfiguration ,
424+ final AppAuthConfiguration appAuthConfiguration ,
425+ final ReadableArray redirectUris ,
426+ final ReadableArray responseTypes ,
427+ final ReadableArray grantTypes ,
428+ final String subjectType ,
429+ final String tokenEndpointAuthMethod ,
430+ final Map <String , String > additionalParametersMap ,
431+ final Promise promise
432+ ) {
433+ final Context context = this .reactContext ;
434+
435+ AuthorizationService authService = new AuthorizationService (context , appAuthConfiguration );
436+
437+ RegistrationRequest .Builder registrationRequestBuilder =
438+ new RegistrationRequest .Builder (
439+ serviceConfiguration ,
440+ arrayToUriList (redirectUris )
441+ )
442+ .setAdditionalParameters (additionalParametersMap );
443+
444+ if (responseTypes != null ) {
445+ registrationRequestBuilder .setResponseTypeValues (arrayToList (responseTypes ));
446+ }
447+
448+ if (grantTypes != null ) {
449+ registrationRequestBuilder .setGrantTypeValues (arrayToList (grantTypes ));
450+ }
451+
452+ if (subjectType != null ) {
453+ registrationRequestBuilder .setSubjectType (subjectType );
454+ }
455+
456+ if (tokenEndpointAuthMethod != null ) {
457+ registrationRequestBuilder .setTokenEndpointAuthenticationMethod (tokenEndpointAuthMethod );
458+ }
459+
460+ RegistrationRequest registrationRequest = registrationRequestBuilder .build ();
461+
462+ AuthorizationService .RegistrationResponseCallback registrationResponseCallback = new AuthorizationService .RegistrationResponseCallback () {
463+ @ Override
464+ public void onRegistrationRequestCompleted (@ Nullable RegistrationResponse response , @ Nullable AuthorizationException ex ) {
465+ if (response != null ) {
466+ WritableMap map = RegistrationResponseFactory .registrationResponseToMap (response );
467+ promise .resolve (map );
468+ } else {
469+ promise .reject ("Failed to refresh token" , getErrorMessage (ex ));
470+ }
471+ }
472+ };
473+
474+ authService .performRegistrationRequest (registrationRequest , registrationResponseCallback );
475+ }
476+
348477 /*
349478 * Authorize user with the provided configuration
350479 */
@@ -487,6 +616,9 @@ private void parseHeaderMap (ReadableMap headerMap) {
487616 if (headerMap == null ) {
488617 return ;
489618 }
619+ if (headerMap .hasKey ("register" ) && headerMap .getType ("register" ) == ReadableType .Map ) {
620+ this .registrationRequestHeaders = MapUtil .readableMapToHashMap (headerMap .getMap ("register" ));
621+ }
490622 if (headerMap .hasKey ("authorize" ) && headerMap .getType ("authorize" ) == ReadableType .Map ) {
491623 this .authorizationRequestHeaders = MapUtil .readableMapToHashMap (headerMap .getMap ("authorize" ));
492624 }
@@ -527,6 +659,28 @@ private String arrayToString(ReadableArray array) {
527659 return strBuilder .toString ();
528660 }
529661
662+ /*
663+ * Create a string list from an array of strings
664+ */
665+ private List <String > arrayToList (ReadableArray array ) {
666+ ArrayList <String > list = new ArrayList <>();
667+ for (int i = 0 ; i < array .size (); i ++) {
668+ list .add (array .getString (i ));
669+ }
670+ return list ;
671+ }
672+
673+ /*
674+ * Create a Uri list from an array of strings
675+ */
676+ private List <Uri > arrayToUriList (ReadableArray array ) {
677+ ArrayList <Uri > list = new ArrayList <>();
678+ for (int i = 0 ; i < array .size (); i ++) {
679+ list .add (Uri .parse (array .getString (i )));
680+ }
681+ return list ;
682+ }
683+
530684 /*
531685 * Create an App Auth configuration using the provided connection builder
532686 */
0 commit comments