Skip to content

Commit 557f284

Browse files
nisrulzLuca Figoli
andauthored
Add methods to request access token synchronous (#5)
Co-authored-by: Luca Figoli <luca.figoli@consultant.aruba.it>
1 parent d5ea814 commit 557f284

File tree

2 files changed

+193
-25
lines changed

2 files changed

+193
-25
lines changed

library/java/net/openid/appauth/AuthState.java

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,128 @@ public void update(@Nullable RegistrationResponse regResponse) {
468468
mAuthorizationException = null;
469469
}
470470

471+
/**
472+
* Ensures that a non-expired access token is available before invoking the provided action.
473+
* @return
474+
*/
475+
@NonNull
476+
public Tokens getSynchronousFreshToken(
477+
@NonNull AuthorizationService service) throws AuthorizationException {
478+
return getSynchronousFreshToken(
479+
service,
480+
NoClientAuthentication.INSTANCE,
481+
Collections.<String, String>emptyMap(),
482+
SystemClock.INSTANCE);
483+
}
484+
485+
/**
486+
* Ensures that a non-expired access token is available before invoking the provided action.
487+
* @return
488+
*/
489+
@NonNull
490+
public Tokens getSynchronousFreshToken(
491+
@NonNull AuthorizationService service,
492+
@NonNull ClientAuthentication clientAuth) throws AuthorizationException {
493+
return getSynchronousFreshToken(
494+
service,
495+
clientAuth,
496+
Collections.<String, String>emptyMap(),
497+
SystemClock.INSTANCE);
498+
}
499+
500+
/**
501+
* Ensures that a non-expired access token is available before invoking the provided action.
502+
* If a token refresh is required, the provided additional parameters will be included in this
503+
* refresh request.
504+
* @return
505+
*/
506+
@NonNull
507+
public Tokens getSynchronousFreshToken(
508+
@NonNull AuthorizationService service,
509+
@NonNull Map<String, String> refreshTokenAdditionalParams) throws ClientAuthentication.UnsupportedAuthenticationMethod, AuthorizationException {
510+
return getSynchronousFreshToken(
511+
service,
512+
getClientAuthentication(),
513+
refreshTokenAdditionalParams,
514+
SystemClock.INSTANCE);
515+
}
516+
517+
/**
518+
* Ensures that a non-expired access token is available before invoking the provided action.
519+
* If a token refresh is required, the provided additional parameters will be included in this
520+
* refresh request.
521+
* @return
522+
*/
523+
@NonNull
524+
public Tokens getSynchronousFreshToken(
525+
@NonNull AuthorizationService service,
526+
@NonNull ClientAuthentication clientAuth,
527+
@NonNull Map<String, String> refreshTokenAdditionalParams) throws AuthorizationException {
528+
return getSynchronousFreshToken(
529+
service,
530+
clientAuth,
531+
refreshTokenAdditionalParams,
532+
SystemClock.INSTANCE);
533+
}
534+
535+
@VisibleForTesting
536+
@NonNull
537+
Tokens getSynchronousFreshToken(
538+
@NonNull final AuthorizationService service,
539+
@NonNull final ClientAuthentication clientAuth,
540+
@NonNull final Map<String, String> refreshTokenAdditionalParams,
541+
@NonNull final Clock clock) throws AuthorizationException {
542+
checkNotNull(service, "service cannot be null");
543+
checkNotNull(clientAuth, "client authentication cannot be null");
544+
checkNotNull(refreshTokenAdditionalParams,
545+
"additional params cannot be null");
546+
checkNotNull(clock, "clock cannot be null");
547+
548+
if (!getNeedsTokenRefresh(clock)) {
549+
String accessToken = getAccessToken();
550+
String idToken = getIdToken();
551+
if (accessToken != null && idToken != null) {
552+
return new Tokens(accessToken, idToken);
553+
}
554+
}
555+
556+
if (mRefreshToken == null) {
557+
throw AuthorizationException.fromTemplate(
558+
AuthorizationRequestErrors.CLIENT_ERROR,
559+
new IllegalStateException("No refresh token available and token have expired"));
560+
}
561+
562+
TokenResponse response = null;
563+
AuthorizationException exception = null;
564+
try {
565+
response = service.performSynchronousTokenRequest(createTokenRefreshRequest(refreshTokenAdditionalParams), clientAuth);
566+
} catch (AuthorizationException e) {
567+
exception = e;
568+
}
569+
570+
update(response, exception);
571+
572+
if (response != null) {
573+
String accessToken = getAccessToken();
574+
String idToken = getIdToken();
575+
if (accessToken != null && idToken != null) {
576+
return new Tokens(accessToken, idToken);
577+
} else {
578+
exception = AuthorizationException.fromTemplate(
579+
AuthorizationException.GeneralErrors.JSON_DESERIALIZATION_ERROR,
580+
new Exception(""));
581+
}
582+
}
583+
584+
if (exception != null) {
585+
throw exception;
586+
} else {
587+
throw AuthorizationException.fromTemplate(
588+
AuthorizationException.GeneralErrors.JSON_DESERIALIZATION_ERROR,
589+
new Exception(""));
590+
}
591+
}
592+
471593
/**
472594
* Ensures that a non-expired access token is available before invoking the provided action.
473595
*/
@@ -764,6 +886,29 @@ void execute(
764886
@Nullable AuthorizationException ex);
765887
}
766888

889+
public static class Tokens {
890+
/**
891+
* Result of the synchronous function that return accessToken
892+
*/
893+
private @NonNull final String accessToken;
894+
private @NonNull final String idToken;
895+
896+
public Tokens(@NonNull String accessToken, @NonNull String idToken) {
897+
this.accessToken = accessToken;
898+
this.idToken = idToken;
899+
}
900+
901+
@NonNull
902+
public String getAccessToken() {
903+
return accessToken;
904+
}
905+
906+
@NonNull
907+
public String getIdToken() {
908+
return idToken;
909+
}
910+
}
911+
767912
/**
768913
* Creates the required client authentication for the token endpoint based on information
769914
* in the most recent registration response (if it is set).

library/java/net/openid/appauth/AuthorizationService.java

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,27 @@ public void performTokenRequest(
512512
.execute();
513513
}
514514

515+
/**
516+
* Sends a request to the authorization service to exchange a code granted as part of an
517+
* authorization request for a token. The result of this request will be sent to the provided
518+
* callback handler.
519+
* @return TokenResponse
520+
*/
521+
public TokenResponse performSynchronousTokenRequest(
522+
@NonNull TokenRequest request,
523+
@NonNull ClientAuthentication clientAuthentication) throws AuthorizationException {
524+
checkNotDisposed();
525+
Logger.debug("Initiating code exchange request to %s",
526+
request.configuration.tokenEndpoint);
527+
TokenRequestTask tokenRequest = new TokenRequestTask(
528+
request,
529+
clientAuthentication,
530+
mClientConfiguration.getConnectionBuilder(),
531+
SystemClock.INSTANCE, null);
532+
JSONObject json = tokenRequest.doInBackground();
533+
return tokenRequest.parseJson(json);
534+
}
535+
515536
/**
516537
* Sends a request to the authorization service to dynamically register a client.
517538
* The result of this request will be sent to the provided callback handler.
@@ -667,51 +688,54 @@ protected JSONObject doInBackground(Void... voids) {
667688

668689
@Override
669690
protected void onPostExecute(JSONObject json) {
691+
try {
692+
TokenResponse tokenResponse = parseJson(json);
693+
mCallback.onTokenRequestCompleted(tokenResponse, null);
694+
} catch (AuthorizationException authorizationException) {
695+
mCallback.onTokenRequestCompleted(null, authorizationException);
696+
}
697+
}
698+
699+
public TokenResponse parseJson(JSONObject json) throws AuthorizationException {
670700
if (mException != null) {
671-
mCallback.onTokenRequestCompleted(null, mException);
672-
return;
701+
throw mException;
673702
}
674703

675704
if (json.has(AuthorizationException.PARAM_ERROR)) {
676705
AuthorizationException ex;
677706
try {
678707
String error = json.getString(AuthorizationException.PARAM_ERROR);
679708
ex = AuthorizationException.fromOAuthTemplate(
680-
TokenRequestErrors.byString(error),
681-
error,
682-
json.optString(AuthorizationException.PARAM_ERROR_DESCRIPTION, null),
683-
UriUtil.parseUriIfAvailable(
684-
json.optString(AuthorizationException.PARAM_ERROR_URI)));
709+
TokenRequestErrors.byString(error),
710+
error,
711+
json.optString(AuthorizationException.PARAM_ERROR_DESCRIPTION, null),
712+
UriUtil.parseUriIfAvailable(
713+
json.optString(AuthorizationException.PARAM_ERROR_URI)));
685714
} catch (JSONException jsonEx) {
686715
ex = AuthorizationException.fromTemplate(
687-
GeneralErrors.JSON_DESERIALIZATION_ERROR,
688-
jsonEx);
716+
GeneralErrors.JSON_DESERIALIZATION_ERROR,
717+
jsonEx);
689718
}
690-
mCallback.onTokenRequestCompleted(null, ex);
691-
return;
719+
throw ex;
692720
}
693721

694722
TokenResponse response;
695723
try {
696724
response = new TokenResponse.Builder(mRequest).fromResponseJson(json).build();
697725
} catch (JSONException jsonEx) {
698-
mCallback.onTokenRequestCompleted(null,
699-
AuthorizationException.fromTemplate(
700-
GeneralErrors.JSON_DESERIALIZATION_ERROR,
701-
jsonEx));
702-
return;
726+
throw AuthorizationException.fromTemplate(
727+
GeneralErrors.JSON_DESERIALIZATION_ERROR,
728+
jsonEx);
703729
}
704730

705731
if (response.idToken != null) {
706732
IdToken idToken;
707733
try {
708734
idToken = IdToken.from(response.idToken);
709735
} catch (IdTokenException | JSONException ex) {
710-
mCallback.onTokenRequestCompleted(null,
711-
AuthorizationException.fromTemplate(
712-
GeneralErrors.ID_TOKEN_PARSING_ERROR,
713-
ex));
714-
return;
736+
throw AuthorizationException.fromTemplate(
737+
GeneralErrors.ID_TOKEN_PARSING_ERROR,
738+
ex);
715739
}
716740

717741
try {
@@ -723,13 +747,12 @@ protected void onPostExecute(JSONObject json) {
723747
mAllowedIssueTimeSkew
724748
);
725749
} catch (AuthorizationException ex) {
726-
mCallback.onTokenRequestCompleted(null, ex);
727-
return;
750+
throw ex;
728751
}
729752
}
730753
Logger.debug("Token exchange with %s completed",
731-
mRequest.configuration.tokenEndpoint);
732-
mCallback.onTokenRequestCompleted(response, null);
754+
mRequest.configuration.tokenEndpoint);
755+
return response;
733756
}
734757

735758
/**

0 commit comments

Comments
 (0)