keycloak-memoizeit

Changes

Details

diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java
index ab5b69d..d989492 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/rotation/AdapterTokenVerifier.java
@@ -74,8 +74,9 @@ public class AdapterTokenVerifier {
             IDToken idToken = TokenVerifier.create(idTokenString, IDToken.class).getToken();
             TokenVerifier<IDToken> idTokenVerifier = TokenVerifier.createWithoutSignature(idToken);
 
-            // Always verify audience on IDToken
+            // Always verify audience and azp on IDToken
             idTokenVerifier.audience(deployment.getResourceName());
+            idTokenVerifier.issuedFor(deployment.getResourceName());
 
             idTokenVerifier.verify();
             return new VerifiedTokens(accessToken, idToken);
diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java
index ddb28aa..4a8547c 100755
--- a/core/src/main/java/org/keycloak/representations/RefreshToken.java
+++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java
@@ -46,7 +46,7 @@ public class RefreshToken extends AccessToken {
         this.issuedFor = token.issuedFor;
         this.sessionState = token.sessionState;
         this.nonce = token.nonce;
-        this.audience = token.audience;
+        this.audience = new String[] { token.issuer };
         this.scope = token.scope;
         if (token.realmAccess != null) {
             realmAccess = token.realmAccess.clone();
diff --git a/core/src/main/java/org/keycloak/TokenVerifier.java b/core/src/main/java/org/keycloak/TokenVerifier.java
index 71e125f..d45e0b2 100755
--- a/core/src/main/java/org/keycloak/TokenVerifier.java
+++ b/core/src/main/java/org/keycloak/TokenVerifier.java
@@ -153,10 +153,8 @@ public class TokenVerifier<T extends JsonWebToken> {
                 throw new VerificationException("No audience in the token");
             }
 
-            for (String aud : audience) {
-                if (expectedAudience.equals(aud)) {
-                    return true;
-                }
+            if (t.hasAudience(expectedAudience)) {
+                return true;
             }
 
             throw new VerificationException("Expected audience not available in the token");
@@ -164,6 +162,29 @@ public class TokenVerifier<T extends JsonWebToken> {
     };
 
 
+    public static class IssuedForCheck implements Predicate<JsonWebToken> {
+
+        private final String expectedIssuedFor;
+
+        public IssuedForCheck(String expectedIssuedFor) {
+            this.expectedIssuedFor = expectedIssuedFor;
+        }
+
+        @Override
+        public boolean test(JsonWebToken jsonWebToken) throws VerificationException {
+            if (expectedIssuedFor == null) {
+                throw new VerificationException("Missing expectedIssuedFor");
+            }
+
+            if (expectedIssuedFor.equals(jsonWebToken.getIssuedFor())) {
+                return true;
+            }
+
+            throw new VerificationException("Expected issuedFor doesn't match");
+        }
+    }
+
+
     private String tokenString;
     private Class<? extends T> clazz;
     private PublicKey publicKey;
@@ -352,6 +373,16 @@ public class TokenVerifier<T extends JsonWebToken> {
         return this.replaceCheck(AudienceCheck.class, true, new AudienceCheck(expectedAudience));
     }
 
+    /**
+     * Add check for verifying that token issuedFor (azp claim) is the expected value
+     *
+     * @param expectedIssuedFor issuedFor, which needs to be in the target token. Can't be null
+     * @return This token verifier
+     */
+    public TokenVerifier<T> issuedFor(String expectedIssuedFor) {
+        return this.replaceCheck(IssuedForCheck.class, true, new IssuedForCheck(expectedIssuedFor));
+    }
+
     public TokenVerifier<T> parse() throws VerificationException {
         if (jws == null) {
             if (tokenString == null) {
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
index 42d64ec..a973eef 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -258,10 +258,13 @@ public class PolicyEvaluationService {
 
         }
 
-        AccessToken.Access realmAccess = accessToken.getRealmAccess();
+        if (representation.getRoleIds() != null && !representation.getRoleIds().isEmpty()) {
+            if (accessToken.getRealmAccess() == null) {
+                accessToken.setRealmAccess(new AccessToken.Access());
+            }
+            AccessToken.Access realmAccess = accessToken.getRealmAccess();
 
-        if (representation.getRoleIds() != null) {
-            representation.getRoleIds().forEach(roleName -> realmAccess.addRole(roleName));
+            representation.getRoleIds().forEach(realmAccess::addRole);
         }
 
         return new CloseableKeycloakIdentity(accessToken, keycloakSession, userSession);
diff --git a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
index 13bc812..5e06676 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java
@@ -64,7 +64,8 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider {
 
     @Override
     protected void processAccessTokenResponse(BrokeredIdentityContext context, AccessTokenResponse response) {
-        JsonWebToken access = validateToken(response.getToken());
+        // Don't verify audience on accessToken as it may not be there. It was verified on IDToken already
+        JsonWebToken access = validateToken(response.getToken(), true);
         context.getContextData().put(VALIDATED_ACCESS_TOKEN, access);
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 872fd4c..2447afa 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -854,6 +854,10 @@ public class TokenEndpoint {
                 .generateAccessToken();
         responseBuilder.getAccessToken().issuedFor(client.getClientId());
 
+        if (audience != null) {
+            responseBuilder.getAccessToken().addAudience(audience);
+        }
+
         if (requestedTokenType.equals(OAuth2Constants.REFRESH_TOKEN_TYPE)) {
             responseBuilder.generateRefreshToken();
             responseBuilder.getRefreshToken().issuedFor(client.getClientId());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index d5ee3e9..ba36588 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -640,7 +640,6 @@ public class TokenManager {
         token.id(KeycloakModelUtils.generateId());
         token.type(TokenUtil.TOKEN_TYPE_BEARER);
         token.subject(user.getId());
-        token.audience(client.getClientId());
         token.issuedNow();
         token.issuedFor(client.getClientId());
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
index 56e5f53..c38cdae 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/MgmtPermissions.java
@@ -96,8 +96,8 @@ class MgmtPermissions implements AdminPermissionEvaluator, AdminPermissionManage
     }
 
     private void initIdentity(KeycloakSession session, AdminAuth auth) {
-        if (auth.getToken().hasAudience(Constants.ADMIN_CLI_CLIENT_ID)
-                || auth.getToken().hasAudience(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
+        if (Constants.ADMIN_CLI_CLIENT_ID.equals(auth.getToken().getIssuedFor())
+                || Constants.ADMIN_CONSOLE_CLIENT_ID.equals(auth.getToken().getIssuedFor())) {
             this.identity = new UserModelIdentity(auth.getRealm(), auth.getUser());
 
         } else {
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 5dd5056..66278a7 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -439,12 +439,15 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
             if (authResult != null) {
                 AccessToken token = authResult.getToken();
-                String[] audience = token.getAudience();
-                ClientModel clientModel = this.realmModel.getClientByClientId(audience[0]);
+                String issuedFor = token.getIssuedFor();
+                ClientModel clientModel = this.realmModel.getClientByClientId(issuedFor);
 
                 if (clientModel == null) {
                     return badRequest("Invalid client.");
                 }
+                if (!clientModel.isEnabled()) {
+                    return badRequest("Client is disabled");
+                }
 
                 session.getContext().setClient(clientModel);
 
diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java
index f8849b0..9bc68df 100644
--- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java
+++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/ClientInitiatedAccountLinkServlet.java
@@ -47,7 +47,7 @@ public class ClientInitiatedAccountLinkServlet extends HttpServlet {
             String realm = request.getParameter("realm");
             KeycloakSecurityContext session = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
             AccessToken token = session.getToken();
-            String clientId = token.getAudience()[0];
+            String clientId = token.getIssuedFor();
             String nonce = UUID.randomUUID().toString();
             MessageDigest md = null;
             try {
diff --git a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java
index 44ebb6d..c43ef97 100644
--- a/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java
+++ b/testsuite/integration-arquillian/test-apps/servlets/src/main/java/org/keycloak/testsuite/adapter/servlet/LinkAndExchangeServlet.java
@@ -126,7 +126,7 @@ public class LinkAndExchangeServlet extends HttpServlet {
             AccessToken token = session.getToken();
             String tokenString = session.getTokenString();
 
-            String clientId = token.getAudience()[0];
+            String clientId = token.getIssuedFor();
             String linkUrl = null;
             try {
                 AccessTokenResponse response = doTokenExchange(realm, tokenString, provider,  clientId, "password");
@@ -176,7 +176,7 @@ public class LinkAndExchangeServlet extends HttpServlet {
                 String realm = request.getParameter("realm");
                 KeycloakSecurityContext session = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
                 AccessToken token = session.getToken();
-                String clientId = token.getAudience()[0];
+                String clientId = token.getIssuedFor();
                 String tokenString = session.getTokenString();
                 AccessTokenResponse response = doTokenExchange(realm, tokenString, provider,  clientId, "password");
                 error = (String)response.getOtherClaims().get("error");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java
index 8ce0632..fe2e886 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java
@@ -307,7 +307,7 @@ public class OIDCJwksClientRegistrationTest extends AbstractClientRegistrationTe
         OAuthClient.AccessTokenResponse accessTokenResponse = doClientCredentialsGrantRequest(signedJwt);
         Assert.assertEquals(200, accessTokenResponse.getStatusCode());
         AccessToken accessToken = oauth.verifyToken(accessTokenResponse.getAccessToken());
-        Assert.assertEquals(response.getClientId(), accessToken.getAudience()[0]);
+        Assert.assertEquals(response.getClientId(), accessToken.getIssuedFor());
     }
 
     private void assertAuthenticateClientError(Map<String, String> generatedKeys, OIDCClientRepresentation response, String kid) throws Exception {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java
index da9d484..3edc3e2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCPairwiseClientRegistrationTest.java
@@ -397,9 +397,6 @@ public class OIDCPairwiseClientRegistrationTest extends AbstractClientRegistrati
         // its iat Claim MUST represent the time that the new ID Token is issued
         Assert.assertEquals(refreshedIdToken.getIssuedAt(), refreshedRefreshToken.getIssuedAt());
 
-        // its aud Claim Value MUST be the same as in the ID Token issued when the original authentication occurred
-        Assert.assertArrayEquals(idToken.getAudience(), refreshedRefreshToken.getAudience());
-
         // if the ID Token contains an auth_time Claim, its value MUST represent the time of the original authentication
         // - not the time that the new ID token is issued
         Assert.assertEquals(idToken.getAuthTime(), refreshedIdToken.getAuthTime());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 167cbf4..6720090 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -143,6 +143,16 @@ public class AccessTokenTest extends AbstractKeycloakTest {
                 .password("password");
         realm.getUsers().add(user.build());
 
+        realm.getClients().stream().filter(clientRepresentation -> {
+
+            return "test-app".equals(clientRepresentation.getClientId());
+
+        }).forEach(clientRepresentation -> {
+
+            clientRepresentation.setFullScopeAllowed(false);
+
+        });
+
         testRealms.add(realm);
 
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java
index f506bdb..db3dd9c 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientTokenExchangeTest.java
@@ -301,7 +301,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
             TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
             AccessToken exchangedToken = verifier.parse().getToken();
             Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
-            Assert.assertEquals("client-exchanger", exchangedToken.getAudience()[0]);
+            Assert.assertNull(exchangedToken.getAudience());
             Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user");
             Assert.assertNull(exchangedToken.getRealmAccess());
         }
@@ -409,7 +409,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
             TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
             AccessToken exchangedToken = verifier.parse().getToken();
             Assert.assertEquals("direct-exchanger", exchangedToken.getIssuedFor());
-            Assert.assertEquals("direct-exchanger", exchangedToken.getAudience()[0]);
+            Assert.assertNull(exchangedToken.getAudience());
             Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user");
             Assert.assertNull(exchangedToken.getRealmAccess());
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
index 416a743..25efa56 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
@@ -228,7 +228,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             assertEquals(Arrays.asList("A","B"), accessToken.getOtherClaims().get("multiValued-via-script"));
 
             // Assert audiences added through AudienceResolve mapper
-            Assert.assertThat(accessToken.getAudience(), arrayContainingInAnyOrder("test-app", "app", "account"));
+            Assert.assertThat(accessToken.getAudience(), arrayContainingInAnyOrder( "app", "account"));
 
             // Assert allowed origins
             String expectedOrigin = UriUtils.getOrigin(oauth.getRedirectUri());
@@ -415,7 +415,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             List<String> roles = (List<String>) cst1.get("roles");
             Assert.assertNames(roles, "offline_access", "user", "customer-user", "hardcoded", AccountRoles.VIEW_PROFILE, AccountRoles.MANAGE_ACCOUNT, AccountRoles.MANAGE_ACCOUNT_LINKS);
 
-            // Assert audience
+            // Assert audience - "test-app" is added due the AudienceResolveProtocolMapper
             Assert.assertNames(Arrays.asList(accessToken.getAudience()), "account", "test-app");
         } finally {
             // Revert
@@ -430,13 +430,15 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
 
 
     @Test
-    public void testAllowedOriginsRemovedFromAccessToken() throws Exception {
+    public void testRolesAndAllowedOriginsRemovedFromAccessToken() throws Exception {
         RealmResource realm = adminClient.realm("test");
         ClientScopeRepresentation allowedOriginsScope = ApiUtil.findClientScopeByName(realm, OIDCLoginProtocolFactory.WEB_ORIGINS_SCOPE).toRepresentation();
+        ClientScopeRepresentation rolesScope = ApiUtil.findClientScopeByName(realm, OIDCLoginProtocolFactory.ROLES_SCOPE).toRepresentation();
 
-        // Remove 'web-origins' scope from the client
+        // Remove 'roles' and 'web-origins' scope from the client
         ClientResource testApp = ApiUtil.findClientByClientId(realm, "test-app");
         testApp.removeDefaultClientScope(allowedOriginsScope.getId());
+        testApp.removeDefaultClientScope(rolesScope.getId());
 
         try {
             OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password");
@@ -445,9 +447,22 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             // Assert web origins are not in the token
             Assert.assertNull(accessToken.getAllowedOrigins());
 
+            // Assert roles are not in the token
+            Assert.assertNull(accessToken.getRealmAccess());
+            Assert.assertTrue(accessToken.getResourceAccess().isEmpty());
+
+            // Assert client not in the token audience. Just in "issuedFor"
+            Assert.assertEquals("test-app", accessToken.getIssuedFor());
+            Assert.assertFalse(accessToken.hasAudience("test-app"));
+
+            // Assert IDToken still has "test-app" as an audience
+            IDToken idToken = oauth.verifyIDToken(response.getIdToken());
+            Assert.assertEquals("test-app", idToken.getIssuedFor());
+            Assert.assertTrue(idToken.hasAudience("test-app"));
         } finally {
             // Revert
             testApp.addDefaultClientScope(allowedOriginsScope.getId());
+            testApp.addDefaultClientScope(rolesScope.getId());
         }
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index bd249d0..8facb41 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -179,6 +179,10 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
         Assert.assertThat(refreshedToken.getExpiration() - token.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10)));
         Assert.assertThat(refreshedRefreshToken.getExpiration() - refreshToken.getExpiration(), allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(10)));
 
+        // "test-app" should not be an audience in the refresh token
+        assertEquals("test-app", refreshedRefreshToken.getIssuedFor());
+        Assert.assertFalse(refreshedRefreshToken.hasAudience("test-app"));
+
         Assert.assertNotEquals(token.getId(), refreshedToken.getId());
         Assert.assertNotEquals(refreshToken.getId(), refreshedRefreshToken.getId());
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java
index a810f5d..7527e05 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AudienceTest.java
@@ -19,6 +19,7 @@ package org.keycloak.testsuite.oidc;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 
 import javax.ws.rs.core.Response;
 
@@ -136,8 +137,8 @@ public class AudienceTest extends AbstractOIDCScopeTest {
                 .user(userId)
                 .assertEvent();
         Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app");
-        // TODO: Frontend client itself should not be in the audiences of access token. Will be fixed in the future
-        assertAudiences(tokens.accessToken, "test-app", "service-client");
+
+        assertAudiences(tokens.accessToken, "service-client");
         assertAudiences(tokens.idToken, "test-app");
 
         // Revert
@@ -168,8 +169,8 @@ public class AudienceTest extends AbstractOIDCScopeTest {
                 .user(userId)
                 .assertEvent();
         Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app");
-        // TODO: Frontend client itself should not be in the audiences of access token. Will be fixed in the future
-        assertAudiences(tokens.accessToken, "test-app", "http://host/service/ctx1", "http://host/service/ctx2");
+
+        assertAudiences(tokens.accessToken, "http://host/service/ctx1", "http://host/service/ctx2");
         assertAudiences(tokens.idToken, "test-app", "http://host/service/ctx2");
 
         // Revert
@@ -192,7 +193,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
                 .user(userId)
                 .assertEvent();
         Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email", "test-app");
-        assertAudiences(tokens.accessToken, "test-app");
+        assertAudiences(tokens.accessToken);
         assertAudiences(tokens.idToken, "test-app");
         Assert.assertFalse(tokens.accessToken.getResourceAccess().containsKey("service-client"));
 
@@ -215,7 +216,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
                 .user(userId)
                 .assertEvent();
         tokens = sendTokenRequest(loginEvent, userId,"openid profile email service-client", "test-app");
-        assertAudiences(tokens.accessToken, "test-app", "service-client");
+        assertAudiences(tokens.accessToken, "service-client");
         assertAudiences(tokens.idToken, "test-app");
         Assert.assertTrue(tokens.accessToken.getResourceAccess().containsKey("service-client"));
         Assert.assertNames(tokens.accessToken.getResourceAccess().get("service-client").getRoles(), "role1");
@@ -228,7 +229,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
 
 
     private void assertAudiences(JsonWebToken token, String... expectedAudience) {
-        Collection<String> audiences = Arrays.asList(token.getAudience());
+        Collection<String> audiences = token.getAudience() == null ? Collections.emptyList() : Arrays.asList(token.getAudience());
         Collection<String> expectedAudiences = Arrays.asList(expectedAudience);
         Assert.assertTrue("Not matched. expectedAudiences: " + expectedAudiences + ", audiences: " + audiences,
                 expectedAudiences.containsAll(audiences) && audiences.containsAll(expectedAudiences));