From c66550ec3e9534a28bc1830e7fa5aa0d4f17dab0 Mon Sep 17 00:00:00 2001 From: Jean-Luc Cenatus Date: Thu, 30 Oct 2025 21:16:21 +0100 Subject: [PATCH 1/3] feat(webauthn): allow Android native origin following the format: android:apk-key-hash: --- .../webauthn/validator/OptionsValidator.java | 25 +- .../io/supertokens/test/webauthn/Utils.java | 12 +- .../api/TestAndroidOriginValidation.java | 272 ++++++++++++++++++ .../api/TestCredentialsRegisterAPI_5_3.java | 2 +- .../test/webauthn/api/TestSignInAPI_5_3.java | 2 +- ...stSignUpWithCredentialRegisterAPI_5_3.java | 2 +- 6 files changed, 309 insertions(+), 6 deletions(-) create mode 100644 src/test/java/io/supertokens/test/webauthn/api/TestAndroidOriginValidation.java diff --git a/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java b/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java index c72a69f19..437e6ee63 100644 --- a/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java +++ b/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java @@ -40,6 +40,29 @@ public static void validateOptions(String origin, String rpId, Long timeout, Str } private static void validateOrigin(String origin, String rpId) throws InvalidWebauthNOptionsException { + // Support Android origins (android:apk-key-hash:) + if (origin.startsWith("android:apk-key-hash:")) { + String hash = origin.substring("android:apk-key-hash:".length()); + + // Validate that the hash is not empty + if (hash.isEmpty()) { + throw new InvalidWebauthNOptionsException("Android origin must contain a valid base64 hash"); + } + + // Accept URL-safe base64 (A-Za-z0-9-_ only) + if (!hash.matches("^[A-Za-z0-9\\-_]+$")) { + throw new InvalidWebauthNOptionsException("Android origin hash must be valid URL-safe base64"); + } + + // Validate length: SHA256 is 32 bytes, base64-urlsafe encoding is 43 chars + if (hash.length() != 43) { + throw new InvalidWebauthNOptionsException("Android origin hash must be 43 characters (base64 of signing certificate's SHA 256 fingerprint)"); + } + + return; + } + + // Validate standard HTTP(S) origins try { URL originUrl = new URL(origin); if (!originUrl.getHost().endsWith(rpId)) { @@ -100,4 +123,4 @@ private static void validateUserPresence(Boolean userPresence) throws InvalidWeb throw new InvalidWebauthNOptionsException("userPresence can't be null"); } } -} \ No newline at end of file +} diff --git a/src/test/java/io/supertokens/test/webauthn/Utils.java b/src/test/java/io/supertokens/test/webauthn/Utils.java index 66f2a2a6d..92486d59d 100644 --- a/src/test/java/io/supertokens/test/webauthn/Utils.java +++ b/src/test/java/io/supertokens/test/webauthn/Utils.java @@ -102,11 +102,15 @@ public static JsonObject registerCredentialForUser(Main main, String email, Stri } public static JsonObject registerOptions(Main main, String email) throws HttpResponseException, IOException { + return registerOptions(main, email, "http://example.com"); + } + + public static JsonObject registerOptions(Main main, String email, String origin) throws HttpResponseException, IOException { JsonObject requestBody = new JsonObject(); requestBody.addProperty("email",email); requestBody.addProperty("relyingPartyName","supertokens.com"); requestBody.addProperty("relyingPartyId","example.com"); - requestBody.addProperty("origin","http://example.com"); + requestBody.addProperty("origin", origin); requestBody.addProperty("timeout",10000); JsonObject response = HttpRequestForTesting.sendJsonPOSTRequest(main, "", @@ -117,10 +121,14 @@ public static JsonObject registerOptions(Main main, String email) throws HttpRes } public static JsonObject signInOptions(Main main) throws HttpResponseException, IOException { + return signInOptions(main, "http://example.com"); + } + + public static JsonObject signInOptions(Main main, String origin) throws HttpResponseException, IOException { JsonObject requestBody = new JsonObject(); requestBody.addProperty("relyingPartyName","supertokens.com"); requestBody.addProperty("relyingPartyId","example.com"); - requestBody.addProperty("origin","http://example.com"); + requestBody.addProperty("origin", origin); requestBody.addProperty("timeout",10000); requestBody.addProperty("userVerification","preferred"); requestBody.addProperty("userPresence",false); diff --git a/src/test/java/io/supertokens/test/webauthn/api/TestAndroidOriginValidation.java b/src/test/java/io/supertokens/test/webauthn/api/TestAndroidOriginValidation.java new file mode 100644 index 000000000..4f26a94e3 --- /dev/null +++ b/src/test/java/io/supertokens/test/webauthn/api/TestAndroidOriginValidation.java @@ -0,0 +1,272 @@ +package io.supertokens.test.webauthn.api; + +import com.google.gson.JsonObject; +import io.supertokens.ProcessState; +import io.supertokens.pluginInterface.STORAGE_TYPE; +import io.supertokens.storageLayer.StorageLayer; +import io.supertokens.test.TestingProcessManager; +import io.supertokens.test.Utils; +import io.supertokens.test.httpRequest.HttpRequestForTesting; +import io.supertokens.test.httpRequest.HttpResponseException; +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 org.junit.Assert.*; + +public class TestAndroidOriginValidation { + @Rule + public TestRule watchman = Utils.getOnFailure(); + + @Rule + public TestRule retryFlaky = Utils.retryFlakyTest(); + + @AfterClass + public static void afterTesting() { + Utils.afterTesting(); + } + + @Before + public void beforeEach() { + Utils.reset(); + } + + @Test + public void testValidAndroidOrigin() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("email", "test@example.com"); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Valid Android origin should be accepted: " + e.getMessage()); + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testValidAndroidOriginWithAlternativeHash() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("email", "test@example.com"); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:sYUC8p5I9SxqFernBPHmDxz_YVZXmVJdW8s-m3RTTqE"); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Valid Android origin with alternative hash should be accepted: " + e.getMessage()); + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testAndroidOriginWithEmptyHash() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("email", "test@example.com"); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:"); + + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("INVALID_OPTIONS_ERROR", resp.get("status").getAsString()); + assertTrue(resp.get("reason").getAsString().contains("Android origin must contain a valid base64 hash")); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testAndroidOriginWithInvalidCharacters() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("email", "test@example.com"); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:invalid@hash#with$special!"); + + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("INVALID_OPTIONS_ERROR", resp.get("status").getAsString()); + assertTrue(resp.get("reason").getAsString().contains("Android origin hash must be valid URL-safe base64")); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testAndroidOriginWithInvalidLength() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("email", "test@example.com"); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:abc"); + + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("INVALID_OPTIONS_ERROR", resp.get("status").getAsString()); + assertTrue(resp.get("reason").getAsString().contains("Android origin hash must be 43 characters")); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testAndroidOriginForSignInOptions() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + JsonObject req = new JsonObject(); + req.addProperty("relyingPartyName", "Example"); + req.addProperty("relyingPartyId", "example.com"); + req.addProperty("origin", "android:apk-key-hash:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"); + req.addProperty("timeout", 10000); + req.addProperty("userVerification", "preferred"); + req.addProperty("userPresence", false); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/signin", req, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Valid Android origin should be accepted for signin options: " + e.getMessage()); + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testMixedOriginsSupport() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + // Test that regular HTTP origins still work + JsonObject req1 = new JsonObject(); + req1.addProperty("email", "test1@example.com"); + req1.addProperty("relyingPartyName", "Example"); + req1.addProperty("relyingPartyId", "example.com"); + req1.addProperty("origin", "http://example.com"); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req1, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Regular HTTP origin should still work: " + e.getMessage()); + } + + // Test that HTTPS origins still work + JsonObject req2 = new JsonObject(); + req2.addProperty("email", "test2@example.com"); + req2.addProperty("relyingPartyName", "Example"); + req2.addProperty("relyingPartyId", "example.com"); + req2.addProperty("origin", "https://example.com"); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req2, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Regular HTTPS origin should still work: " + e.getMessage()); + } + + // Test that Android origins work + JsonObject req3 = new JsonObject(); + req3.addProperty("email", "test3@example.com"); + req3.addProperty("relyingPartyName", "Example"); + req3.addProperty("relyingPartyId", "example.com"); + req3.addProperty("origin", "android:apk-key-hash:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"); + + try { + JsonObject resp = HttpRequestForTesting.sendJsonPOSTRequest(process.getProcess(), "", + "http://localhost:3567/recipe/webauthn/options/register", req3, 1000, 1000, null, + SemVer.v5_3.get(), "webauthn"); + assertEquals("OK", resp.get("status").getAsString()); + } catch (HttpResponseException e) { + fail("Android origin should work alongside HTTP(S) origins: " + e.getMessage()); + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } +} diff --git a/src/test/java/io/supertokens/test/webauthn/api/TestCredentialsRegisterAPI_5_3.java b/src/test/java/io/supertokens/test/webauthn/api/TestCredentialsRegisterAPI_5_3.java index e98578a8e..c0ba35e00 100644 --- a/src/test/java/io/supertokens/test/webauthn/api/TestCredentialsRegisterAPI_5_3.java +++ b/src/test/java/io/supertokens/test/webauthn/api/TestCredentialsRegisterAPI_5_3.java @@ -351,4 +351,4 @@ private void checkResponseStructure(JsonObject resp) throws Exception { assertTrue(resp.has("relyingPartyName")); assertTrue(resp.has("recipeUserId")); } -} \ No newline at end of file +} diff --git a/src/test/java/io/supertokens/test/webauthn/api/TestSignInAPI_5_3.java b/src/test/java/io/supertokens/test/webauthn/api/TestSignInAPI_5_3.java index 520146d70..2fe3db363 100644 --- a/src/test/java/io/supertokens/test/webauthn/api/TestSignInAPI_5_3.java +++ b/src/test/java/io/supertokens/test/webauthn/api/TestSignInAPI_5_3.java @@ -376,4 +376,4 @@ private void checkResponseStructure(JsonObject resp) throws Exception { assertTrue(resp.has("recipeUserId")); } -} \ No newline at end of file +} diff --git a/src/test/java/io/supertokens/test/webauthn/api/TestSignUpWithCredentialRegisterAPI_5_3.java b/src/test/java/io/supertokens/test/webauthn/api/TestSignUpWithCredentialRegisterAPI_5_3.java index aae7d15ae..0e32a2232 100644 --- a/src/test/java/io/supertokens/test/webauthn/api/TestSignUpWithCredentialRegisterAPI_5_3.java +++ b/src/test/java/io/supertokens/test/webauthn/api/TestSignUpWithCredentialRegisterAPI_5_3.java @@ -286,4 +286,4 @@ private void checkResponseStructure(JsonObject resp) throws Exception { assertTrue(resp.has("relyingPartyName")); assertTrue(resp.has("recipeUserId")); } -} \ No newline at end of file +} From 61883f2f5b98e6c07ed14a22021ce41234e79b31 Mon Sep 17 00:00:00 2001 From: Jean-Luc Cenatus Date: Wed, 19 Nov 2025 17:22:52 +0100 Subject: [PATCH 2/3] chore(webauthn): in OptionsValidator, use java.util.Base64 when applicable --- .../webauthn/validator/OptionsValidator.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java b/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java index 437e6ee63..223b5b882 100644 --- a/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java +++ b/src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java @@ -22,6 +22,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.Base64; import java.util.List; public class OptionsValidator { @@ -49,14 +50,21 @@ private static void validateOrigin(String origin, String rpId) throws InvalidWeb throw new InvalidWebauthNOptionsException("Android origin must contain a valid base64 hash"); } - // Accept URL-safe base64 (A-Za-z0-9-_ only) - if (!hash.matches("^[A-Za-z0-9\\-_]+$")) { - throw new InvalidWebauthNOptionsException("Android origin hash must be valid URL-safe base64"); + // Validate base64 characters first before checking length + try { + Base64.getUrlDecoder().decode(hash); + } catch (IllegalArgumentException error) { + throw new InvalidWebauthNOptionsException("Android origin hash must be valid URL-safe base64 (no padding)"); } - // Validate length: SHA256 is 32 bytes, base64-urlsafe encoding is 43 chars + // SHA-256 fingerprint in base64url (no padding) is always 43 characters and decodes to 32 bytes if (hash.length() != 43) { - throw new InvalidWebauthNOptionsException("Android origin hash must be 43 characters (base64 of signing certificate's SHA 256 fingerprint)"); + throw new InvalidWebauthNOptionsException("Android origin hash must be 43 characters (base64url SHA-256)"); + } + + // Verify it decodes to exactly 32 bytes (SHA-256) + if (Base64.getUrlDecoder().decode(hash).length != 32) { + throw new InvalidWebauthNOptionsException("Android origin hash must decode to 32 bytes (SHA-256)"); } return; From 34150cbd8dd0bb635481a8513942edc990180a6b Mon Sep 17 00:00:00 2001 From: Jean-Luc Cenatus Date: Fri, 21 Nov 2025 11:24:34 +0100 Subject: [PATCH 3/3] docs: update CHANGELOG.md --- CHANGELOG.md | 181 ++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea6fdece..ee2110f87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Adds SAML features - Fixes potential deadlock issue with `TelemetryProvider` - Adds DeadlockLogger as an utility for discovering deadlock issues +- Adds support for Android native origins (those starting with `android:apk-key-hash:`) in WebAuthn ### Migration @@ -116,7 +117,7 @@ CREATE INDEX IF NOT EXISTS saml_claims_expires_at_index ON saml_claims (expires_ ## [11.0.0] - Migrates tests to Github Actions -- Updates JRE to 21. +- Updates JRE to 21. ## [10.1.4] @@ -194,7 +195,7 @@ CREATE TABLE IF NOT EXISTS webauthn_account_recovery_tokens ( token VARCHAR(256) NOT NULL, expires_at BIGINT NOT NULL, CONSTRAINT webauthn_account_recovery_token_pkey PRIMARY KEY (app_id, tenant_id, user_id, token), - CONSTRAINT webauthn_account_recovery_token_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES + CONSTRAINT webauthn_account_recovery_token_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES all_auth_recipe_users(app_id, tenant_id, user_id) ON DELETE CASCADE ); @@ -238,7 +239,7 @@ CREATE TABLE IF NOT EXISTS webauthn_user_to_tenant ( email VARCHAR(256) NOT NULL, CONSTRAINT webauthn_user_to_tenant_email_key UNIQUE (app_id, tenant_id, email), CONSTRAINT webauthn_user_to_tenant_pkey PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT webauthn_user_to_tenant_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES + CONSTRAINT webauthn_user_to_tenant_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES all_auth_recipe_users(app_id, tenant_id, user_id) ON DELETE CASCADE ); @@ -249,7 +250,7 @@ CREATE TABLE IF NOT EXISTS webauthn_users ( rp_id VARCHAR(256) NOT NULL, time_joined BIGINT NOT NULL, CONSTRAINT webauthn_users_pkey PRIMARY KEY (app_id, user_id), - CONSTRAINT webauthn_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id(app_id, + CONSTRAINT webauthn_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id(app_id, user_id) ON DELETE CASCADE ); @@ -275,7 +276,7 @@ CREATE TABLE IF NOT EXISTS webauthn_account_recovery_tokens ( token VARCHAR(256) NOT NULL, expires_at BIGINT NOT NULL, CONSTRAINT webauthn_account_recovery_token_pkey PRIMARY KEY (app_id, tenant_id, user_id, token), - CONSTRAINT webauthn_account_recovery_token_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES + CONSTRAINT webauthn_account_recovery_token_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES all_auth_recipe_users(app_id, tenant_id, user_id) ON DELETE CASCADE ); @@ -319,7 +320,7 @@ CREATE TABLE IF NOT EXISTS webauthn_user_to_tenant ( email VARCHAR(256) NOT NULL, CONSTRAINT webauthn_user_to_tenant_email_key UNIQUE (app_id, tenant_id, email), CONSTRAINT webauthn_user_to_tenant_pkey PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT webauthn_user_to_tenant_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES + CONSTRAINT webauthn_user_to_tenant_user_id_fkey FOREIGN KEY (app_id, tenant_id, user_id) REFERENCES all_auth_recipe_users(app_id, tenant_id, user_id) ON DELETE CASCADE ); @@ -330,7 +331,7 @@ CREATE TABLE IF NOT EXISTS webauthn_users ( rp_id VARCHAR(256) NOT NULL, time_joined BIGINT NOT NULL, CONSTRAINT webauthn_users_pkey PRIMARY KEY (app_id, user_id), - CONSTRAINT webauthn_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, + CONSTRAINT webauthn_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE ); @@ -425,8 +426,8 @@ CREATE TABLE IF NOT EXISTS bulk_import_users ( raw_data TEXT NOT NULL, status VARCHAR(128) DEFAULT 'NEW', error_msg TEXT, - created_at BIGINT NOT NULL, - updated_at BIGINT NOT NULL, + created_at BIGINT NOT NULL, + updated_at BIGINT NOT NULL, CONSTRAINT bulk_import_users_pkey PRIMARY KEY(app_id, id), CONSTRAINT bulk_import_users__app_id_fkey FOREIGN KEY(app_id) REFERENCES apps(app_id) ON DELETE CASCADE ); @@ -434,7 +435,7 @@ CREATE TABLE IF NOT EXISTS bulk_import_users ( CREATE INDEX IF NOT EXISTS bulk_import_users_status_updated_at_index ON bulk_import_users (app_id, status, updated_at); CREATE INDEX IF NOT EXISTS bulk_import_users_pagination_index1 ON bulk_import_users (app_id, status, created_at DESC, id DESC); - + CREATE INDEX IF NOT EXISTS bulk_import_users_pagination_index2 ON bulk_import_users (app_id, created_at DESC, id DESC); CREATE INDEX IF NOT EXISTS session_info_user_id_app_id_index ON session_info (user_id, app_id); @@ -450,8 +451,8 @@ CREATE TABLE IF NOT EXISTS bulk_import_users ( raw_data TEXT NOT NULL, status VARCHAR(128) DEFAULT 'NEW', error_msg TEXT, - created_at BIGINT UNSIGNED NOT NULL, - updated_at BIGINT UNSIGNED NOT NULL, + created_at BIGINT UNSIGNED NOT NULL, + updated_at BIGINT UNSIGNED NOT NULL, PRIMARY KEY (app_id, id), FOREIGN KEY(app_id) REFERENCES apps(app_id) ON DELETE CASCADE ); @@ -459,7 +460,7 @@ CREATE TABLE IF NOT EXISTS bulk_import_users ( CREATE INDEX bulk_import_users_status_updated_at_index ON bulk_import_users (app_id, status, updated_at); CREATE INDEX bulk_import_users_pagination_index1 ON bulk_import_users (app_id, status, created_at DESC, id DESC); - + CREATE INDEX bulk_import_users_pagination_index2 ON bulk_import_users (app_id, created_at DESC, id DESC); CREATE INDEX session_info_user_id_app_id_index ON session_info (user_id, app_id); @@ -616,7 +617,7 @@ CREATE INDEX oauth_logout_challenges_time_created_index ON oauth_logout_challeng ## [9.2.3] - 2024-10-09 - Adds support for `--with-temp-dir` in CLI and `tempDirLocation=` in Core -- Adds validation to firstFactors and requiredSecondaryFactors names while creating tenants/apps/etc. to not allow +- Adds validation to firstFactors and requiredSecondaryFactors names while creating tenants/apps/etc. to not allow special chars. ## [9.2.2] - 2024-09-04 @@ -654,7 +655,7 @@ CREATE INDEX user_last_active_last_active_time_index ON user_last_active (last_a ### Fixes -- Account linking now properly checks if the login methods of the primary user can be shared with the tenants of the +- Account linking now properly checks if the login methods of the primary user can be shared with the tenants of the recipe user we are trying to link - Simplifying email verification token creation @@ -1136,7 +1137,7 @@ multiple times without any issue. Follow the steps below to run the script: CREATE INDEX all_auth_recipe_users_recipe_id_index ON all_auth_recipe_users (app_id, recipe_id, tenant_id); - ALTER TABLE emailpassword_pswd_reset_tokens + ALTER TABLE emailpassword_pswd_reset_tokens DROP FOREIGN KEY emailpassword_pswd_reset_tokens_ibfk_1; ALTER TABLE emailpassword_pswd_reset_tokens @@ -1277,7 +1278,7 @@ multiple times without any issue. Follow the steps below to run the script: CONSTRAINT apps_pkey PRIMARY KEY(app_id) ); - INSERT INTO apps (app_id, created_at_time) + INSERT INTO apps (app_id, created_at_time) VALUES ('public', 0) ON CONFLICT DO NOTHING; ------------------------------------------------------------ @@ -1292,7 +1293,7 @@ multiple times without any issue. Follow the steps below to run the script: REFERENCES apps (app_id) ON DELETE CASCADE ); - INSERT INTO tenants (app_id, tenant_id, created_at_time) + INSERT INTO tenants (app_id, tenant_id, created_at_time) VALUES ('public', 'public', 0) ON CONFLICT DO NOTHING; CREATE INDEX IF NOT EXISTS tenants_app_id_index ON tenants (app_id); @@ -1307,14 +1308,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT key_value_pkey; ALTER TABLE key_value - ADD CONSTRAINT key_value_pkey + ADD CONSTRAINT key_value_pkey PRIMARY KEY (app_id, tenant_id, name); ALTER TABLE key_value DROP CONSTRAINT IF EXISTS key_value_tenant_id_fkey; ALTER TABLE key_value - ADD CONSTRAINT key_value_tenant_id_fkey + ADD CONSTRAINT key_value_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1332,7 +1333,7 @@ multiple times without any issue. Follow the steps below to run the script: FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE ); - INSERT INTO app_id_to_user_id (user_id, recipe_id) + INSERT INTO app_id_to_user_id (user_id, recipe_id) SELECT user_id, recipe_id FROM all_auth_recipe_users ON CONFLICT DO NOTHING; @@ -1348,14 +1349,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT all_auth_recipe_users_pkey CASCADE; ALTER TABLE all_auth_recipe_users - ADD CONSTRAINT all_auth_recipe_users_pkey + ADD CONSTRAINT all_auth_recipe_users_pkey PRIMARY KEY (app_id, tenant_id, user_id); ALTER TABLE all_auth_recipe_users DROP CONSTRAINT IF EXISTS all_auth_recipe_users_tenant_id_fkey; ALTER TABLE all_auth_recipe_users - ADD CONSTRAINT all_auth_recipe_users_tenant_id_fkey + ADD CONSTRAINT all_auth_recipe_users_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1363,7 +1364,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS all_auth_recipe_users_user_id_fkey; ALTER TABLE all_auth_recipe_users - ADD CONSTRAINT all_auth_recipe_users_user_id_fkey + ADD CONSTRAINT all_auth_recipe_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; @@ -1454,14 +1455,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT session_info_pkey CASCADE; ALTER TABLE session_info - ADD CONSTRAINT session_info_pkey + ADD CONSTRAINT session_info_pkey PRIMARY KEY (app_id, tenant_id, session_handle); ALTER TABLE session_info DROP CONSTRAINT IF EXISTS session_info_tenant_id_fkey; ALTER TABLE session_info - ADD CONSTRAINT session_info_tenant_id_fkey + ADD CONSTRAINT session_info_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1478,14 +1479,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT session_access_token_signing_keys_pkey CASCADE; ALTER TABLE session_access_token_signing_keys - ADD CONSTRAINT session_access_token_signing_keys_pkey + ADD CONSTRAINT session_access_token_signing_keys_pkey PRIMARY KEY (app_id, created_at_time); ALTER TABLE session_access_token_signing_keys DROP CONSTRAINT IF EXISTS session_access_token_signing_keys_app_id_fkey; ALTER TABLE session_access_token_signing_keys - ADD CONSTRAINT session_access_token_signing_keys_app_id_fkey + ADD CONSTRAINT session_access_token_signing_keys_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -1500,14 +1501,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT jwt_signing_keys_pkey CASCADE; ALTER TABLE jwt_signing_keys - ADD CONSTRAINT jwt_signing_keys_pkey + ADD CONSTRAINT jwt_signing_keys_pkey PRIMARY KEY (app_id, key_id); ALTER TABLE jwt_signing_keys DROP CONSTRAINT IF EXISTS jwt_signing_keys_app_id_fkey; ALTER TABLE jwt_signing_keys - ADD CONSTRAINT jwt_signing_keys_app_id_fkey + ADD CONSTRAINT jwt_signing_keys_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -1522,14 +1523,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT emailverification_verified_emails_pkey CASCADE; ALTER TABLE emailverification_verified_emails - ADD CONSTRAINT emailverification_verified_emails_pkey + ADD CONSTRAINT emailverification_verified_emails_pkey PRIMARY KEY (app_id, user_id, email); ALTER TABLE emailverification_verified_emails DROP CONSTRAINT IF EXISTS emailverification_verified_emails_app_id_fkey; ALTER TABLE emailverification_verified_emails - ADD CONSTRAINT emailverification_verified_emails_app_id_fkey + ADD CONSTRAINT emailverification_verified_emails_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -1545,14 +1546,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT emailverification_tokens_pkey CASCADE; ALTER TABLE emailverification_tokens - ADD CONSTRAINT emailverification_tokens_pkey + ADD CONSTRAINT emailverification_tokens_pkey PRIMARY KEY (app_id, tenant_id, user_id, email, token); ALTER TABLE emailverification_tokens DROP CONSTRAINT IF EXISTS emailverification_tokens_tenant_id_fkey; ALTER TABLE emailverification_tokens - ADD CONSTRAINT emailverification_tokens_tenant_id_fkey + ADD CONSTRAINT emailverification_tokens_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1570,14 +1571,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS emailpassword_users_email_key CASCADE; ALTER TABLE emailpassword_users - ADD CONSTRAINT emailpassword_users_pkey + ADD CONSTRAINT emailpassword_users_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE emailpassword_users DROP CONSTRAINT IF EXISTS emailpassword_users_user_id_fkey; ALTER TABLE emailpassword_users - ADD CONSTRAINT emailpassword_users_user_id_fkey + ADD CONSTRAINT emailpassword_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; @@ -1624,14 +1625,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT emailpassword_pswd_reset_tokens_pkey CASCADE; ALTER TABLE emailpassword_pswd_reset_tokens - ADD CONSTRAINT emailpassword_pswd_reset_tokens_pkey + ADD CONSTRAINT emailpassword_pswd_reset_tokens_pkey PRIMARY KEY (app_id, user_id, token); ALTER TABLE emailpassword_pswd_reset_tokens DROP CONSTRAINT IF EXISTS emailpassword_pswd_reset_tokens_user_id_fkey; ALTER TABLE emailpassword_pswd_reset_tokens - ADD CONSTRAINT emailpassword_pswd_reset_tokens_user_id_fkey + ADD CONSTRAINT emailpassword_pswd_reset_tokens_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES emailpassword_users (app_id, user_id) ON DELETE CASCADE; @@ -1646,7 +1647,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT passwordless_users_pkey CASCADE; ALTER TABLE passwordless_users - ADD CONSTRAINT passwordless_users_pkey + ADD CONSTRAINT passwordless_users_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE passwordless_users @@ -1659,7 +1660,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS passwordless_users_user_id_fkey; ALTER TABLE passwordless_users - ADD CONSTRAINT passwordless_users_user_id_fkey + ADD CONSTRAINT passwordless_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; @@ -1703,14 +1704,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT passwordless_devices_pkey CASCADE; ALTER TABLE passwordless_devices - ADD CONSTRAINT passwordless_devices_pkey + ADD CONSTRAINT passwordless_devices_pkey PRIMARY KEY (app_id, tenant_id, device_id_hash); ALTER TABLE passwordless_devices DROP CONSTRAINT IF EXISTS passwordless_devices_tenant_id_fkey; ALTER TABLE passwordless_devices - ADD CONSTRAINT passwordless_devices_tenant_id_fkey + ADD CONSTRAINT passwordless_devices_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1734,14 +1735,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT passwordless_codes_pkey CASCADE; ALTER TABLE passwordless_codes - ADD CONSTRAINT passwordless_codes_pkey + ADD CONSTRAINT passwordless_codes_pkey PRIMARY KEY (app_id, tenant_id, code_id); ALTER TABLE passwordless_codes DROP CONSTRAINT IF EXISTS passwordless_codes_device_id_hash_fkey; ALTER TABLE passwordless_codes - ADD CONSTRAINT passwordless_codes_device_id_hash_fkey + ADD CONSTRAINT passwordless_codes_device_id_hash_fkey FOREIGN KEY (app_id, tenant_id, device_id_hash) REFERENCES passwordless_devices (app_id, tenant_id, device_id_hash) ON DELETE CASCADE; @@ -1774,14 +1775,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS thirdparty_users_user_id_key CASCADE; ALTER TABLE thirdparty_users - ADD CONSTRAINT thirdparty_users_pkey + ADD CONSTRAINT thirdparty_users_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE thirdparty_users DROP CONSTRAINT IF EXISTS thirdparty_users_user_id_fkey; ALTER TABLE thirdparty_users - ADD CONSTRAINT thirdparty_users_user_id_fkey + ADD CONSTRAINT thirdparty_users_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; @@ -1837,7 +1838,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS userid_mapping_pkey CASCADE; ALTER TABLE userid_mapping - ADD CONSTRAINT userid_mapping_pkey + ADD CONSTRAINT userid_mapping_pkey PRIMARY KEY (app_id, supertokens_user_id, external_user_id); ALTER TABLE userid_mapping @@ -1858,7 +1859,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS userid_mapping_supertokens_user_id_fkey; ALTER TABLE userid_mapping - ADD CONSTRAINT userid_mapping_supertokens_user_id_fkey + ADD CONSTRAINT userid_mapping_supertokens_user_id_fkey FOREIGN KEY (app_id, supertokens_user_id) REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; @@ -1873,14 +1874,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT roles_pkey CASCADE; ALTER TABLE roles - ADD CONSTRAINT roles_pkey + ADD CONSTRAINT roles_pkey PRIMARY KEY (app_id, role); ALTER TABLE roles DROP CONSTRAINT IF EXISTS roles_app_id_fkey; ALTER TABLE roles - ADD CONSTRAINT roles_app_id_fkey + ADD CONSTRAINT roles_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -1895,14 +1896,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT role_permissions_pkey CASCADE; ALTER TABLE role_permissions - ADD CONSTRAINT role_permissions_pkey + ADD CONSTRAINT role_permissions_pkey PRIMARY KEY (app_id, role, permission); ALTER TABLE role_permissions DROP CONSTRAINT IF EXISTS role_permissions_role_fkey; ALTER TABLE role_permissions - ADD CONSTRAINT role_permissions_role_fkey + ADD CONSTRAINT role_permissions_role_fkey FOREIGN KEY (app_id, role) REFERENCES roles (app_id, role) ON DELETE CASCADE; @@ -1922,14 +1923,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT user_roles_pkey CASCADE; ALTER TABLE user_roles - ADD CONSTRAINT user_roles_pkey + ADD CONSTRAINT user_roles_pkey PRIMARY KEY (app_id, tenant_id, user_id, role); ALTER TABLE user_roles DROP CONSTRAINT IF EXISTS user_roles_tenant_id_fkey; ALTER TABLE user_roles - ADD CONSTRAINT user_roles_tenant_id_fkey + ADD CONSTRAINT user_roles_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -1937,7 +1938,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS user_roles_role_fkey; ALTER TABLE user_roles - ADD CONSTRAINT user_roles_role_fkey + ADD CONSTRAINT user_roles_role_fkey FOREIGN KEY (app_id, role) REFERENCES roles (app_id, role) ON DELETE CASCADE; @@ -1958,14 +1959,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT user_metadata_pkey CASCADE; ALTER TABLE user_metadata - ADD CONSTRAINT user_metadata_pkey + ADD CONSTRAINT user_metadata_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE user_metadata DROP CONSTRAINT IF EXISTS user_metadata_app_id_fkey; ALTER TABLE user_metadata - ADD CONSTRAINT user_metadata_app_id_fkey + ADD CONSTRAINT user_metadata_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -1980,7 +1981,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT dashboard_users_pkey CASCADE; ALTER TABLE dashboard_users - ADD CONSTRAINT dashboard_users_pkey + ADD CONSTRAINT dashboard_users_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE dashboard_users @@ -1994,7 +1995,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS dashboard_users_app_id_fkey; ALTER TABLE dashboard_users - ADD CONSTRAINT dashboard_users_app_id_fkey + ADD CONSTRAINT dashboard_users_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -2009,14 +2010,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT dashboard_user_sessions_pkey CASCADE; ALTER TABLE dashboard_user_sessions - ADD CONSTRAINT dashboard_user_sessions_pkey + ADD CONSTRAINT dashboard_user_sessions_pkey PRIMARY KEY (app_id, session_id); ALTER TABLE dashboard_user_sessions DROP CONSTRAINT IF EXISTS dashboard_user_sessions_user_id_fkey; ALTER TABLE dashboard_user_sessions - ADD CONSTRAINT dashboard_user_sessions_user_id_fkey + ADD CONSTRAINT dashboard_user_sessions_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES dashboard_users (app_id, user_id) ON DELETE CASCADE; @@ -2031,14 +2032,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT totp_users_pkey CASCADE; ALTER TABLE totp_users - ADD CONSTRAINT totp_users_pkey + ADD CONSTRAINT totp_users_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE totp_users DROP CONSTRAINT IF EXISTS totp_users_app_id_fkey; ALTER TABLE totp_users - ADD CONSTRAINT totp_users_app_id_fkey + ADD CONSTRAINT totp_users_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -2053,14 +2054,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT totp_user_devices_pkey; ALTER TABLE totp_user_devices - ADD CONSTRAINT totp_user_devices_pkey + ADD CONSTRAINT totp_user_devices_pkey PRIMARY KEY (app_id, user_id, device_name); ALTER TABLE totp_user_devices DROP CONSTRAINT IF EXISTS totp_user_devices_user_id_fkey; ALTER TABLE totp_user_devices - ADD CONSTRAINT totp_user_devices_user_id_fkey + ADD CONSTRAINT totp_user_devices_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; @@ -2076,14 +2077,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT totp_used_codes_pkey CASCADE; ALTER TABLE totp_used_codes - ADD CONSTRAINT totp_used_codes_pkey + ADD CONSTRAINT totp_used_codes_pkey PRIMARY KEY (app_id, tenant_id, user_id, created_time_ms); ALTER TABLE totp_used_codes DROP CONSTRAINT IF EXISTS totp_used_codes_user_id_fkey; ALTER TABLE totp_used_codes - ADD CONSTRAINT totp_used_codes_user_id_fkey + ADD CONSTRAINT totp_used_codes_user_id_fkey FOREIGN KEY (app_id, user_id) REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; @@ -2091,7 +2092,7 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT IF EXISTS totp_used_codes_tenant_id_fkey; ALTER TABLE totp_used_codes - ADD CONSTRAINT totp_used_codes_tenant_id_fkey + ADD CONSTRAINT totp_used_codes_tenant_id_fkey FOREIGN KEY (app_id, tenant_id) REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; @@ -2112,14 +2113,14 @@ multiple times without any issue. Follow the steps below to run the script: DROP CONSTRAINT user_last_active_pkey CASCADE; ALTER TABLE user_last_active - ADD CONSTRAINT user_last_active_pkey + ADD CONSTRAINT user_last_active_pkey PRIMARY KEY (app_id, user_id); ALTER TABLE user_last_active DROP CONSTRAINT IF EXISTS user_last_active_app_id_fkey; ALTER TABLE user_last_active - ADD CONSTRAINT user_last_active_app_id_fkey + ADD CONSTRAINT user_last_active_app_id_fkey FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; @@ -2143,10 +2144,10 @@ multiple times without any issue. Follow the steps below to run the script: BEGIN DECLARE done INT DEFAULT FALSE; DECLARE dropCommand VARCHAR(255); - DECLARE dropCur CURSOR for - SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP FOREIGN KEY ', constraint_name, ';') + DECLARE dropCur CURSOR for + SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP FOREIGN KEY ', constraint_name, ';') FROM information_schema.table_constraints - WHERE constraint_type='FOREIGN KEY' + WHERE constraint_type='FOREIGN KEY' AND table_schema = DATABASE() AND table_name in ( 'all_auth_recipe_users', @@ -2202,10 +2203,10 @@ multiple times without any issue. Follow the steps below to run the script: BEGIN DECLARE done INT DEFAULT FALSE; DECLARE dropCommand VARCHAR(255); - DECLARE dropCur CURSOR for - SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP PRIMARY KEY ', ';') + DECLARE dropCur CURSOR for + SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP PRIMARY KEY ', ';') FROM information_schema.table_constraints - WHERE constraint_type='PRIMARY KEY' + WHERE constraint_type='PRIMARY KEY' AND table_schema = DATABASE() AND table_name in ( 'all_auth_recipe_users', @@ -2261,10 +2262,10 @@ multiple times without any issue. Follow the steps below to run the script: BEGIN DECLARE done INT DEFAULT FALSE; DECLARE dropCommand VARCHAR(255); - DECLARE dropCur CURSOR for - SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP INDEX ', constraint_name, ';') + DECLARE dropCur CURSOR for + SELECT concat('ALTER TABLE ', table_schema,'.',table_name,' DROP INDEX ', constraint_name, ';') FROM information_schema.table_constraints - WHERE constraint_type='UNIQUE' + WHERE constraint_type='UNIQUE' AND table_schema = DATABASE() AND table_name in ( 'all_auth_recipe_users', @@ -2320,10 +2321,10 @@ multiple times without any issue. Follow the steps below to run the script: BEGIN DECLARE done INT DEFAULT FALSE; DECLARE dropCommand VARCHAR(255); - DECLARE dropCur CURSOR for + DECLARE dropCur CURSOR for SELECT DISTINCT concat('ALTER TABLE ', table_schema, '.', table_name, ' DROP INDEX ', index_name, ';') FROM information_schema.statistics - WHERE NON_UNIQUE = 1 + WHERE NON_UNIQUE = 1 AND table_schema = database() AND table_name in ( 'all_auth_recipe_users', @@ -2376,7 +2377,7 @@ multiple times without any issue. Follow the steps below to run the script: -- CREATE PROCEDURE st_add_column_if_not_exists( - IN p_table_name varchar(50), + IN p_table_name varchar(50), IN p_column_name varchar(50), IN p_column_type varchar(50), IN p_additional varchar(100), @@ -2384,14 +2385,14 @@ multiple times without any issue. Follow the steps below to run the script: READS SQL DATA BEGIN DECLARE v_count INT; - + # Check wether column exist or not SELECT count(*) INTO v_count FROM information_schema.columns WHERE table_schema = database() AND table_name = p_table_name AND column_name = p_column_name; - + IF v_count > 0 THEN # Return column already exists message SELECT 'Column already Exists' INTO p_status_message; @@ -2411,7 +2412,7 @@ multiple times without any issue. Follow the steps below to run the script: CALL st_drop_all_fkeys(); CALL st_drop_all_keys(); CALL st_drop_all_pkeys(); - CALL st_drop_all_indexes(); + CALL st_drop_all_indexes(); -- General Tables @@ -2423,7 +2424,7 @@ multiple times without any issue. Follow the steps below to run the script: ALTER TABLE apps ADD PRIMARY KEY(app_id); - INSERT IGNORE INTO apps (app_id, created_at_time) + INSERT IGNORE INTO apps (app_id, created_at_time) VALUES ('public', 0); -- @@ -2441,7 +2442,7 @@ multiple times without any issue. Follow the steps below to run the script: ADD FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; - INSERT IGNORE INTO tenants (app_id, tenant_id, created_at_time) + INSERT IGNORE INTO tenants (app_id, tenant_id, created_at_time) VALUES ('public', 'public', 0); -- @@ -2471,7 +2472,7 @@ multiple times without any issue. Follow the steps below to run the script: ADD FOREIGN KEY (app_id) REFERENCES apps (app_id) ON DELETE CASCADE; - INSERT IGNORE INTO app_id_to_user_id (user_id, recipe_id) + INSERT IGNORE INTO app_id_to_user_id (user_id, recipe_id) SELECT user_id, recipe_id FROM all_auth_recipe_users; @@ -3065,13 +3066,13 @@ multiple times without any issue. Follow the steps below to run the script: { "$project": { "keys": 0, - + } }, { "$merge": { "into": "jwt_signing_keys", - + } } ]);