diff --git a/CHANGELOG.md b/CHANGELOG.md
index df9077ecd..a344b44ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
 to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [9.2.4] 
+
+- Adds support for CDI 5.2
+- In CDI 5.2, when creating a new session for a known user, checks if the user is a member of that tenant.
+  If not, returns UNAUTHORISED.
+
 ## [9.2.3] - 2024-10-09
 
 - Adds support for `--with-temp-dir` in CLI and `tempDirLocation=` in Core
diff --git a/build.gradle b/build.gradle
index 7ede11ac5..28e1025fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
 //    }
 //}
 
-version = "9.2.3"
+version = "9.2.4"
 
 
 repositories {
diff --git a/coreDriverInterfaceSupported.json b/coreDriverInterfaceSupported.json
index aa87aab03..130c4b2c1 100644
--- a/coreDriverInterfaceSupported.json
+++ b/coreDriverInterfaceSupported.json
@@ -20,6 +20,7 @@
     "3.1",
     "4.0",
     "5.0",
-    "5.1"
+    "5.1",
+    "5.2"
   ]
 }
diff --git a/src/main/java/io/supertokens/session/Session.java b/src/main/java/io/supertokens/session/Session.java
index 380068a5e..4e4439c10 100644
--- a/src/main/java/io/supertokens/session/Session.java
+++ b/src/main/java/io/supertokens/session/Session.java
@@ -19,6 +19,7 @@
 import com.google.gson.JsonObject;
 import io.supertokens.Main;
 import io.supertokens.ProcessState;
+import io.supertokens.authRecipe.AuthRecipe;
 import io.supertokens.config.Config;
 import io.supertokens.config.CoreConfig;
 import io.supertokens.exceptions.AccessTokenPayloadError;
@@ -53,6 +54,7 @@
 import io.supertokens.storageLayer.StorageLayer;
 import io.supertokens.useridmapping.UserIdMapping;
 import io.supertokens.useridmapping.UserIdType;
+import io.supertokens.utils.SemVer;
 import io.supertokens.utils.Utils;
 import org.jetbrains.annotations.TestOnly;
 
@@ -82,7 +84,7 @@ public static SessionInformationHolder createNewSession(TenantIdentifier tenantI
             JWT.JWTException, UnsupportedJWTSigningAlgorithmException, AccessTokenPayloadError {
         try {
             return createNewSession(tenantIdentifier, storage, main, recipeUserId, userDataInJWT, userDataInDatabase,
-                    false, AccessToken.getLatestVersion(), false);
+                    false, AccessToken.getLatestVersion(), false, null);
         } catch (TenantOrAppNotFoundException e) {
             throw new IllegalStateException(e);
         }
@@ -101,8 +103,9 @@ public static SessionInformationHolder createNewSession(Main main,
         try {
             return createNewSession(
                     new TenantIdentifier(null, null, null), storage, main,
-                    recipeUserId, userDataInJWT, userDataInDatabase, false, AccessToken.getLatestVersion(), false);
-        } catch (TenantOrAppNotFoundException e) {
+                    recipeUserId, userDataInJWT, userDataInDatabase, false,
+                    AccessToken.getLatestVersion(), false, null);
+        } catch (TenantOrAppNotFoundException | UnauthorisedException e) {
             throw new IllegalStateException(e);
         }
     }
@@ -121,8 +124,8 @@ public static SessionInformationHolder createNewSession(Main main, @Nonnull Stri
         try {
             return createNewSession(
                     new TenantIdentifier(null, null, null), storage, main,
-                    recipeUserId, userDataInJWT, userDataInDatabase, enableAntiCsrf, version, useStaticKey);
-        } catch (TenantOrAppNotFoundException e) {
+                    recipeUserId, userDataInJWT, userDataInDatabase, enableAntiCsrf, version, useStaticKey, null);
+        } catch (TenantOrAppNotFoundException | UnauthorisedException e) {
             throw new IllegalStateException(e);
         }
     }
@@ -132,11 +135,11 @@ public static SessionInformationHolder createNewSession(TenantIdentifier tenantI
                                                             @Nonnull JsonObject userDataInJWT,
                                                             @Nonnull JsonObject userDataInDatabase,
                                                             boolean enableAntiCsrf, AccessToken.VERSION version,
-                                                            boolean useStaticKey)
+                                                            boolean useStaticKey, SemVer semVer)
             throws NoSuchAlgorithmException, StorageQueryException, InvalidKeyException,
             InvalidKeySpecException, StorageTransactionLogicException, SignatureException, IllegalBlockSizeException,
             BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException, AccessTokenPayloadError,
-            UnsupportedJWTSigningAlgorithmException, TenantOrAppNotFoundException {
+            UnsupportedJWTSigningAlgorithmException, TenantOrAppNotFoundException, UnauthorisedException {
         String sessionHandle = UUID.randomUUID().toString();
         if (!tenantIdentifier.getTenantId().equals(TenantIdentifier.DEFAULT_TENANT_ID)) {
             sessionHandle += "_" + tenantIdentifier.getTenantId();
@@ -151,6 +154,7 @@ public static SessionInformationHolder createNewSession(TenantIdentifier tenantI
                 recipeUserId = userIdMapping.superTokensUserId;
             }
 
+
             primaryUserId = StorageUtils.getAuthRecipeStorage(storage)
                     .getPrimaryUserIdStrForUserId(tenantIdentifier.toAppIdentifier(), recipeUserId);
             if (primaryUserId == null) {
@@ -166,6 +170,16 @@ public static SessionInformationHolder createNewSession(TenantIdentifier tenantI
             if (userIdMappings.containsKey(recipeUserId)) {
                 recipeUserId = userIdMappings.get(recipeUserId);
             }
+
+            if(semVer!= null && semVer.greaterThanOrEqualTo(SemVer.v5_2)) {
+                AuthRecipeUserInfo authRecipeUserInfo = AuthRecipe.getUserById(tenantIdentifier.toAppIdentifier(),
+                        storage, recipeUserId);
+                if (authRecipeUserInfo != null) {
+                    if (!authRecipeUserInfo.tenantIds.contains(tenantIdentifier.getTenantId())) {
+                        throw new UnauthorisedException("User is not part of requested tenant!");
+                    }
+                }
+            }
         }
 
         String antiCsrfToken = enableAntiCsrf ? UUID.randomUUID().toString() : null;
diff --git a/src/main/java/io/supertokens/utils/SemVer.java b/src/main/java/io/supertokens/utils/SemVer.java
index 6c94518c3..ef43014af 100644
--- a/src/main/java/io/supertokens/utils/SemVer.java
+++ b/src/main/java/io/supertokens/utils/SemVer.java
@@ -37,6 +37,7 @@ public class SemVer implements Comparable<SemVer> {
     public static final SemVer v4_0 = new SemVer("4.0");
     public static final SemVer v5_0 = new SemVer("5.0");
     public static final SemVer v5_1 = new SemVer("5.1");
+    public static final SemVer v5_2 = new SemVer("5.2");
 
     final private String version;
 
diff --git a/src/main/java/io/supertokens/webserver/WebserverAPI.java b/src/main/java/io/supertokens/webserver/WebserverAPI.java
index 3cf62be23..33cb703a7 100644
--- a/src/main/java/io/supertokens/webserver/WebserverAPI.java
+++ b/src/main/java/io/supertokens/webserver/WebserverAPI.java
@@ -29,7 +29,8 @@
 import io.supertokens.pluginInterface.Storage;
 import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException;
 import io.supertokens.pluginInterface.exceptions.StorageQueryException;
-import io.supertokens.pluginInterface.multitenancy.*;
+import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
+import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
 import io.supertokens.pluginInterface.multitenancy.exceptions.TenantOrAppNotFoundException;
 import io.supertokens.storageLayer.StorageLayer;
 import io.supertokens.useridmapping.UserIdType;
@@ -76,10 +77,11 @@ public abstract class WebserverAPI extends HttpServlet {
         supportedVersions.add(SemVer.v4_0);
         supportedVersions.add(SemVer.v5_0);
         supportedVersions.add(SemVer.v5_1);
+        supportedVersions.add(SemVer.v5_2);
     }
 
     public static SemVer getLatestCDIVersion() {
-        return SemVer.v5_1;
+        return SemVer.v5_2;
     }
 
     public SemVer getLatestCDIVersionForRequest(HttpServletRequest req)
diff --git a/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java b/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java
index 7af0fa841..127db70f5 100644
--- a/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java
+++ b/src/main/java/io/supertokens/webserver/api/session/SessionAPI.java
@@ -103,7 +103,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
             SessionInformationHolder sessionInfo = Session.createNewSession(
                     tenantIdentifier, storage, main, userId, userDataInJWT,
                     userDataInDatabase, enableAntiCsrf, accessTokenVersion,
-                    useStaticSigningKey);
+                    useStaticSigningKey, version);
 
             if (storage.getType() == STORAGE_TYPE.SQL) {
                 try {
@@ -143,6 +143,11 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I
             super.sendJsonResponse(200, result, resp);
         } catch (AccessTokenPayloadError e) {
             throw new ServletException(new BadRequestException(e.getMessage()));
+        } catch (UnauthorisedException e) {
+                JsonObject reply = new JsonObject();
+                reply.addProperty("status", "UNAUTHORISED");
+                reply.addProperty("message", e.getMessage());
+                super.sendJsonResponse(200, reply, resp);
         } catch (NoSuchAlgorithmException | StorageQueryException | InvalidKeyException | InvalidKeySpecException |
                  StorageTransactionLogicException | SignatureException | IllegalBlockSizeException |
                  BadPaddingException | InvalidAlgorithmParameterException | NoSuchPaddingException |
diff --git a/src/test/java/io/supertokens/test/accountlinking/SessionTests.java b/src/test/java/io/supertokens/test/accountlinking/SessionTests.java
index ac12a8c9a..cbb9de093 100644
--- a/src/test/java/io/supertokens/test/accountlinking/SessionTests.java
+++ b/src/test/java/io/supertokens/test/accountlinking/SessionTests.java
@@ -386,7 +386,7 @@ public void testSessionBehaviourWhenUserBelongsTo2TenantsAndThenLinkedToSomeOthe
 
         AuthRecipe.createPrimaryUser(process.getProcess(), t1.toAppIdentifier(), t1Storage,
                 user2.getSupertokensUserId());
-        AuthRecipe.linkAccounts(process.getProcess(), t1.toAppIdentifier(), t1Storage, user1.getSupertokensUserId(),
+        AuthRecipe.linkAccounts(process.getProcess(), t2.toAppIdentifier(), t2Storage, user1.getSupertokensUserId(),
                 user2.getSupertokensUserId());
 
         SessionInformationHolder session1 = Session.createNewSession(t2, t2Storage, process.getProcess(),
diff --git a/src/test/java/io/supertokens/test/session/TenantCheckForKnownUsersTest.java b/src/test/java/io/supertokens/test/session/TenantCheckForKnownUsersTest.java
new file mode 100644
index 000000000..c8ea41cc0
--- /dev/null
+++ b/src/test/java/io/supertokens/test/session/TenantCheckForKnownUsersTest.java
@@ -0,0 +1,273 @@
+/*
+ *    Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ *    This software is licensed under the Apache License, Version 2.0 (the
+ *    "License") as published by the Apache Software Foundation.
+ *
+ *    You may not use this file except in compliance with the License. You may
+ *    obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ */
+
+package io.supertokens.test.session;
+
+import com.google.gson.JsonObject;
+import io.supertokens.ProcessState;
+import io.supertokens.emailpassword.EmailPassword;
+import io.supertokens.exceptions.UnauthorisedException;
+import io.supertokens.multitenancy.Multitenancy;
+import io.supertokens.pluginInterface.Storage;
+import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo;
+import io.supertokens.pluginInterface.multitenancy.*;
+import io.supertokens.session.Session;
+import io.supertokens.session.accessToken.AccessToken;
+import io.supertokens.session.info.SessionInformationHolder;
+import io.supertokens.storageLayer.StorageLayer;
+import io.supertokens.test.TestingProcessManager;
+import io.supertokens.test.Utils;
+import io.supertokens.utils.SemVer;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class TenantCheckForKnownUsersTest {
+    @Rule
+    public TestRule watchman = Utils.getOnFailure();
+
+    @AfterClass
+    public static void afterTesting() {
+        Utils.afterTesting();
+    }
+
+    @Before
+    public void beforeEach() {
+        Utils.reset();
+    }
+
+    @Test
+    public void verifyUnknownUsersSessionCreationWorks() throws Exception {
+
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        String userId = "userId-not-existing";
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        SessionInformationHolder sessionInfo = Session.createNewSession(new TenantIdentifier(null, null, null), StorageLayer.getBaseStorage(process.getProcess()),
+                process.getProcess(), userId, userDataInJWT, userDataInDatabase, true, AccessToken.getLatestVersion(), false,
+                SemVer.v5_2);
+
+        JsonObject sessionData = Session.getSession(process.getProcess(),
+                sessionInfo.session.handle).userDataInDatabase;
+        assertEquals(userDataInDatabase.toString(), sessionData.toString());
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+    @Test
+    public void verifyKnownUsersWithRightTenantSessionCreationWorks() throws Exception {
+
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        TenantIdentifier app = new TenantIdentifier(null, "a1", null);
+        TenantIdentifier tenant = new TenantIdentifier(null, "a1", "t1");
+
+        // Create tenants
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                app,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                tenant,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Storage appStorage = (
+                StorageLayer.getStorage(app, process.getProcess()));
+        Storage tenantStorage = (
+                StorageLayer.getStorage(tenant, process.getProcess()));
+
+
+        AuthRecipeUserInfo user = EmailPassword.signUp(app, appStorage, process.getProcess(), "test@example.com",
+                "password");
+        String userId = user.getSupertokensUserId();
+
+        Multitenancy.addUserIdToTenant(process.getProcess(), tenant, tenantStorage, userId);
+
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        SessionInformationHolder sessionInfo = Session.createNewSession(new TenantIdentifier(null, "a1", "t1"), StorageLayer.getBaseStorage(process.getProcess()),
+                    process.getProcess(), userId, userDataInJWT, userDataInDatabase, true, AccessToken.getLatestVersion(), false,
+                SemVer.v5_2);
+
+        JsonObject sessionData = Session.getSession(new TenantIdentifier(null, "a1", "t1"),
+                StorageLayer.getBaseStorage(process.getProcess()), sessionInfo.session.handle).userDataInDatabase;
+        assertEquals(userDataInDatabase.toString(), sessionData.toString());
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+    @Test
+    public void verifyKnownUsersSessionCreationWithWrongTenantThrows() throws Exception {
+
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        TenantIdentifier app = new TenantIdentifier(null, "a1", null);
+        TenantIdentifier tenant = new TenantIdentifier(null, "a1", "t1");
+        TenantIdentifier tenant2 = new TenantIdentifier(null, "a1", "t2");
+
+        // Create tenants
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                app,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                tenant,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                tenant2,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Storage appStorage = (
+                StorageLayer.getStorage(app, process.getProcess()));
+        Storage tenantStorage = (
+                StorageLayer.getStorage(tenant, process.getProcess()));
+
+
+        AuthRecipeUserInfo user = EmailPassword.signUp(app, appStorage, process.getProcess(), "test@example.com",
+                "password");
+        String userId = user.getSupertokensUserId();
+
+        Multitenancy.addUserIdToTenant(process.getProcess(), tenant, tenantStorage, userId); //user only added to tenant!
+
+
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+
+        try {
+            SessionInformationHolder sessionInfo = Session.createNewSession(tenant2, StorageLayer.getBaseStorage(process.getProcess()),
+                    process.getProcess(), userId, userDataInJWT, userDataInDatabase, true, AccessToken.getLatestVersion(), false,
+                    SemVer.v5_2);
+
+            fail();
+        } catch (UnauthorisedException e) {
+            //pass
+        }
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+    @Test
+    public void verifyKnownUsersSessionCreationWithWrongTenantDoesntThrowWithLesserCDI() throws Exception {
+
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        TenantIdentifier app = new TenantIdentifier(null, "a1", null);
+        TenantIdentifier tenant = new TenantIdentifier(null, "a1", "t1");
+        TenantIdentifier tenant2 = new TenantIdentifier(null, "a1", "t2");
+
+        // Create tenants
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                app,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                tenant,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Multitenancy.addNewOrUpdateAppOrTenant(process.getProcess(), new TenantConfig(
+                tenant2,
+                new EmailPasswordConfig(true),
+                new ThirdPartyConfig(true, null),
+                new PasswordlessConfig(true),
+                null, null, new JsonObject()
+        ), false);
+
+        Storage appStorage = (
+                StorageLayer.getStorage(app, process.getProcess()));
+        Storage tenantStorage = (
+                StorageLayer.getStorage(tenant, process.getProcess()));
+
+
+        AuthRecipeUserInfo user = EmailPassword.signUp(app, appStorage, process.getProcess(), "test@example.com",
+                "password");
+        String userId = user.getSupertokensUserId();
+
+        Multitenancy.addUserIdToTenant(process.getProcess(), tenant, tenantStorage, userId); //user only added to tenant!
+
+
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        SessionInformationHolder sessionInfo = Session.createNewSession(tenant2, StorageLayer.getBaseStorage(process.getProcess()),
+                process.getProcess(), userId, userDataInJWT, userDataInDatabase, true, AccessToken.getLatestVersion(), false,
+                SemVer.v5_1);
+
+        JsonObject sessionData = Session.getSession(tenant2, StorageLayer.getBaseStorage(process.getProcess()), sessionInfo.session.handle).userDataInDatabase;
+        assertEquals(userDataInDatabase.toString(), sessionData.toString());
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+}
diff --git a/src/test/java/io/supertokens/test/session/api/SessionAPITest5_2.java b/src/test/java/io/supertokens/test/session/api/SessionAPITest5_2.java
new file mode 100644
index 000000000..605b60d4b
--- /dev/null
+++ b/src/test/java/io/supertokens/test/session/api/SessionAPITest5_2.java
@@ -0,0 +1,283 @@
+/*
+ *    Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ *    This software is licensed under the Apache License, Version 2.0 (the
+ *    "License") as published by the Apache Software Foundation.
+ *
+ *    You may not use this file except in compliance with the License. You may
+ *    obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ *    License for the specific language governing permissions and limitations
+ *    under the License.
+ */
+
+package io.supertokens.test.session.api;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import io.supertokens.ProcessState;
+import io.supertokens.session.accessToken.AccessToken;
+import io.supertokens.session.jwt.JWT;
+import io.supertokens.test.TestingProcessManager;
+import io.supertokens.test.Utils;
+import io.supertokens.test.httpRequest.HttpRequestForTesting;
+import io.supertokens.utils.SemVer;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
+import java.util.UUID;
+
+import static junit.framework.TestCase.*;
+import static org.junit.Assert.assertNotNull;
+
+public class SessionAPITest5_2 {
+    @Rule
+    public TestRule watchman = Utils.getOnFailure();
+
+    @AfterClass
+    public static void afterTesting() {
+        Utils.afterTesting();
+    }
+
+    @Before
+    public void beforeEach() {
+        Utils.reset();
+    }
+
+    @Test
+    public void successOutputCheck() throws Exception {
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        String userId = "userId";
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        JsonObject request = new JsonObject();
+        request.addProperty("userId", userId);
+        request.add("userDataInJWT", userDataInJWT);
+        request.add("userDataInDatabase", userDataInDatabase);
+        request.addProperty("useStaticKey", false);
+        request.addProperty("enableAntiCsrf", false);
+
+        JsonObject response = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "",
+                "http://localhost:3567/recipe/session", request, 1000, 1000, null, SemVer.v5_2.get(),
+                "session");
+        checkSessionResponse(response, process, userId, userDataInJWT, false);
+        assertFalse(response.has("antiCsrfToken"));
+
+        String iat = "" + JWT.getPayloadWithoutVerifying(
+                response.get("accessToken").getAsJsonObject().get("token").getAsString()).payload.get("iat").getAsInt();
+        assertEquals(10, iat.length());
+        //noinspection ResultOfMethodCallIgnored
+        Long.parseLong(iat); // We are checking that this doesn't throw, it would if it was in exponential form
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+
+    }
+
+    @Test
+    public void badInputTest() throws Exception {
+
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        String userId = "userId";
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        try {
+            JsonObject userDataInJWT = new JsonObject();
+            userDataInJWT.addProperty("sub", "value");
+
+            JsonObject request = new JsonObject();
+            request.addProperty("userId", userId);
+            request.add("userDataInJWT", userDataInJWT);
+            request.add("userDataInDatabase", userDataInDatabase);
+            request.addProperty("enableAntiCsrf", false);
+            HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", "http://localhost:3567/recipe/session",
+                    request, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), "session");
+            fail();
+        } catch (io.supertokens.test.httpRequest.HttpResponseException e) {
+            assertEquals(e.statusCode, 400);
+            assertEquals(e.getMessage(),
+                    "Http error. Status Code: 400. Message: The user payload contains protected field");
+        }
+
+        try {
+            JsonObject userDataInJWT = new JsonObject();
+            userDataInJWT.addProperty("rsub", "value");
+
+            JsonObject request = new JsonObject();
+            request.addProperty("userId", userId);
+            request.add("userDataInJWT", userDataInJWT);
+            request.add("userDataInDatabase", userDataInDatabase);
+            request.addProperty("enableAntiCsrf", false);
+            HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", "http://localhost:3567/recipe/session",
+                    request, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), "session");
+            fail();
+        } catch (io.supertokens.test.httpRequest.HttpResponseException e) {
+            assertEquals(e.statusCode, 400);
+            assertEquals(e.getMessage(),
+                    "Http error. Status Code: 400. Message: The user payload contains protected field");
+        }
+
+        try {
+            JsonObject userDataInJWT = new JsonObject();
+            userDataInJWT.addProperty("tId", "t1");
+
+            JsonObject request = new JsonObject();
+            request.addProperty("userId", userId);
+            request.add("userDataInJWT", userDataInJWT);
+            request.add("userDataInDatabase", userDataInDatabase);
+            request.addProperty("enableAntiCsrf", false);
+            HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", "http://localhost:3567/recipe/session",
+                    request, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), "session");
+            fail();
+        } catch (io.supertokens.test.httpRequest.HttpResponseException e) {
+            assertEquals(e.statusCode, 400);
+            assertEquals(e.getMessage(),
+                    "Http error. Status Code: 400. Message: The user payload contains protected field");
+        }
+
+        try {
+            JsonObject userDataInJWT = new JsonObject();
+            userDataInJWT.addProperty("exp", "value");
+
+            JsonObject request = new JsonObject();
+            request.addProperty("userId", userId);
+            request.add("userDataInJWT", userDataInJWT);
+            request.add("userDataInDatabase", userDataInDatabase);
+            request.addProperty("enableAntiCsrf", false);
+            HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", "http://localhost:3567/recipe/session",
+                    request, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), "session");
+            fail();
+        } catch (io.supertokens.test.httpRequest.HttpResponseException e) {
+            assertEquals(e.statusCode, 400);
+            assertEquals(e.getMessage(),
+                    "Http error. Status Code: 400. Message: The user payload contains protected field");
+        }
+
+        try {
+            JsonObject userDataInJWT = new JsonObject();
+            userDataInJWT.addProperty("sessionHandle", "value");
+
+            JsonObject request = new JsonObject();
+            request.addProperty("userId", userId);
+            request.add("userDataInJWT", userDataInJWT);
+            request.add("userDataInDatabase", userDataInDatabase);
+            request.addProperty("enableAntiCsrf", false);
+            HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", "http://localhost:3567/recipe/session",
+                    request, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), "session");
+            fail();
+        } catch (io.supertokens.test.httpRequest.HttpResponseException e) {
+            assertEquals(e.statusCode, 400);
+            assertEquals(e.getMessage(),
+                    "Http error. Status Code: 400. Message: The user payload contains protected field");
+        }
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+    @Test
+    public void successOutputCheckWithStatic() throws Exception {
+        String[] args = {"../"};
+        TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
+
+        String userId = "userId";
+        JsonObject userDataInJWT = new JsonObject();
+        userDataInJWT.addProperty("key", "value");
+        JsonObject userDataInDatabase = new JsonObject();
+        userDataInDatabase.addProperty("key", "value");
+
+        JsonObject request = new JsonObject();
+        request.addProperty("userId", userId);
+        request.add("userDataInJWT", userDataInJWT);
+        request.add("userDataInDatabase", userDataInDatabase);
+        request.addProperty("useDynamicSigningKey", false);
+        request.addProperty("enableAntiCsrf", false);
+
+        JsonObject response = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "",
+                "http://localhost:3567/recipe/session", request, 1000, 1000, null, SemVer.v5_2.get(),
+                "session");
+        checkSessionResponse(response, process, userId, userDataInJWT, true);
+        assertFalse(response.has("antiCsrfToken"));
+
+        process.kill();
+        assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
+    }
+
+    public static void checkSessionResponse(JsonObject response, TestingProcessManager.TestingProcess process,
+                                            String userId, JsonObject userDataInJWT, boolean isStatic)
+            throws JWT.JWTException {
+        assertNotNull(response.get("session").getAsJsonObject().get("handle").getAsString());
+        assertEquals(response.get("session").getAsJsonObject().get("userId").getAsString(), userId);
+        assertEquals(response.get("session").getAsJsonObject().get("userDataInJWT").getAsJsonObject().toString(),
+                userDataInJWT.toString());
+        assertEquals(response.get("session").getAsJsonObject().get("tenantId").getAsString(), "public");
+        assertEquals(response.get("session").getAsJsonObject().get("recipeUserId").getAsString(), userId);
+        assertEquals(response.get("session").getAsJsonObject().entrySet().size(), 5);
+
+        assertTrue(response.get("accessToken").getAsJsonObject().has("token"));
+        assertTrue(response.get("accessToken").getAsJsonObject().has("expiry"));
+        assertTrue(response.get("accessToken").getAsJsonObject().has("createdTime"));
+        assertEquals(response.get("accessToken").getAsJsonObject().entrySet().size(), 3);
+
+        assertTrue(response.get("refreshToken").getAsJsonObject().has("token"));
+        assertTrue(response.get("refreshToken").getAsJsonObject().has("expiry"));
+        assertTrue(response.get("refreshToken").getAsJsonObject().has("createdTime"));
+        assertEquals(response.get("refreshToken").getAsJsonObject().entrySet().size(), 3);
+
+        JWT.JWTPreParseInfo preParseInfo = JWT.preParseJWTInfo(
+                response.get("accessToken").getAsJsonObject().get("token").getAsString());
+        assertEquals(preParseInfo.version, AccessToken.VERSION.V5);
+        assertNotNull(preParseInfo.kid);
+
+        IllegalArgumentException caught = null;
+        try {
+            // We are just checking the format basically;
+            UUID.fromString(preParseInfo.kid.substring(2));
+        } catch (IllegalArgumentException ex) {
+            caught = ex;
+        }
+
+        if (isStatic) {
+            assertNull(caught);
+            assertEquals("s-", preParseInfo.kid.substring(0, 2));
+        } else {
+            assertNotNull(caught);
+            assertEquals("d-", preParseInfo.kid.substring(0, 2));
+        }
+
+        Base64.getUrlDecoder().decode(preParseInfo.header);
+        Base64.getUrlDecoder().decode(preParseInfo.signature);
+
+
+        JsonObject payload = new JsonParser().parse(
+                        new String(Base64.getUrlDecoder().decode(preParseInfo.payload), StandardCharsets.UTF_8))
+                .getAsJsonObject();
+        assertFalse(payload.has("userData"));
+
+        for (Map.Entry<String, JsonElement> entry : userDataInJWT.entrySet()) {
+            assertTrue(payload.has(entry.getKey()));
+            assertEquals(payload.get(entry.getKey()).toString(), userDataInJWT.get(entry.getKey()).toString());
+        }
+    }
+}