diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 26d012b..3a7e4c0 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -269,6 +269,12 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
}
private Response checkOIDCParams() {
+ // If request is not OIDC request, but pure OAuth2 request and response_type is just 'token', then 'nonce' is not mandatory
+ boolean isOIDCRequest = TokenUtil.isOIDCRequest(request.getScope());
+ if (!isOIDCRequest && parsedResponseType.toString().equals(OIDCResponseType.TOKEN)) {
+ return null;
+ }
+
if (parsedResponseType.isImplicitOrHybridFlow() && request.getNonce() == null) {
ServicesLogger.LOGGER.missingParameter(OIDCLoginProtocol.NONCE_PARAM);
event.error(Errors.INVALID_REQUEST);
@@ -354,10 +360,12 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
private void checkRedirectUri() {
String redirectUriParam = request.getRedirectUriParam();
+ boolean isOIDCRequest = TokenUtil.isOIDCRequest(request.getScope());
event.detail(Details.REDIRECT_URI, redirectUriParam);
- redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUriParam, realm, client);
+ // redirect_uri parameter is required per OpenID Connect, but optional per OAuth2
+ redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUriParam, realm, client, isOIDCRequest);
if (redirectUri == null) {
event.error(Errors.INVALID_REDIRECT_URI);
throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
index 60f5493..c61bdd0 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
@@ -26,6 +26,7 @@ import org.keycloak.services.Urls;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -38,12 +39,16 @@ public class RedirectUtils {
public static String verifyRealmRedirectUri(UriInfo uriInfo, String redirectUri, RealmModel realm) {
Set<String> validRedirects = getValidateRedirectUris(uriInfo, realm);
- return verifyRedirectUri(uriInfo, null, redirectUri, realm, validRedirects);
+ return verifyRedirectUri(uriInfo, null, redirectUri, realm, validRedirects, true);
}
public static String verifyRedirectUri(UriInfo uriInfo, String redirectUri, RealmModel realm, ClientModel client) {
+ return verifyRedirectUri(uriInfo, redirectUri, realm, client, true);
+ }
+
+ public static String verifyRedirectUri(UriInfo uriInfo, String redirectUri, RealmModel realm, ClientModel client, boolean requireRedirectUri) {
if (client != null)
- return verifyRedirectUri(uriInfo, client.getRootUrl(), redirectUri, realm, client.getRedirectUris());
+ return verifyRedirectUri(uriInfo, client.getRootUrl(), redirectUri, realm, client.getRedirectUris(), requireRedirectUri);
return null;
}
@@ -69,10 +74,16 @@ public class RedirectUtils {
return redirects;
}
- private static String verifyRedirectUri(UriInfo uriInfo, String rootUrl, String redirectUri, RealmModel realm, Set<String> validRedirects) {
+ private static String verifyRedirectUri(UriInfo uriInfo, String rootUrl, String redirectUri, RealmModel realm, Set<String> validRedirects, boolean requireRedirectUri) {
if (redirectUri == null) {
- logger.debug("No Redirect URI parameter specified");
- return null;
+ if (!requireRedirectUri) {
+ redirectUri = getSingleValidRedirectUri(validRedirects);
+ }
+
+ if (redirectUri == null) {
+ logger.debug("No Redirect URI parameter specified");
+ return null;
+ }
} else if (validRedirects.isEmpty()) {
logger.debug("No Redirect URIs supplied");
redirectUri = null;
@@ -149,4 +160,14 @@ public class RedirectUtils {
return false;
}
+ private static String getSingleValidRedirectUri(Collection<String> validRedirects) {
+ if (validRedirects.size() != 1) return null;
+ String validRedirect = validRedirects.iterator().next();
+ int idx = validRedirect.indexOf("/*");
+ if (idx > -1) {
+ validRedirect = validRedirect.substring(0, idx);
+ }
+ return validRedirect;
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/ServicesLogger.java b/services/src/main/java/org/keycloak/services/ServicesLogger.java
index bd239a6..2d6c473 100644
--- a/services/src/main/java/org/keycloak/services/ServicesLogger.java
+++ b/services/src/main/java/org/keycloak/services/ServicesLogger.java
@@ -406,7 +406,7 @@ public interface ServicesLogger extends BasicLogger {
void failedToCloseProviderSession(@Cause Throwable t);
@LogMessage(level = WARN)
- @Message(id=91, value="Request is missing scope 'openid' so it's not treated as OIDC, but just pure OAuth2 request. This can have impact in future versions (eg. removed IDToken from the Token Response)")
+ @Message(id=91, value="Request is missing scope 'openid' so it's not treated as OIDC, but just pure OAuth2 request.")
@Once
void oidcScopeMissing();
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
index 4c89eaa..207a317 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
@@ -102,7 +102,7 @@ public class OAuthClient {
private String maxAge;
- private String responseType = OAuth2Constants.CODE;
+ private String responseType;
private String responseMode;
@@ -171,6 +171,8 @@ public class OAuthClient {
clientSessionState = null;
clientSessionHost = null;
maxAge = null;
+ responseType = OAuth2Constants.CODE;
+ responseMode = null;
nonce = null;
request = null;
requestUri = null;