diff --git a/CHANGELOG.md b/CHANGELOG.md index a929e921e..c2c999110 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [6.0.0] - 2023-06-02 +### Adds + +- Support for multitenancy. +- New config `supertokens_saas_secret` added to support multitenancy in SaaS mode. +- New config `supertokens_default_cdi_version` is added to specify the version of CDI core must assume when the + version is not specified in the request. If this config is not specified, the core will assume the latest version. + ### Fixes - Fixes an issue where session verification would fail for JWTs created using the JWT recipe @@ -36,1381 +43,1544 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Migration steps for SQL -
- -If using PostgreSQL - -#### Run the following SQL script - -```sql --- General Tables - -CREATE TABLE IF NOT EXISTS apps ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - created_at_time BIGINT, - CONSTRAINT apps_pkey PRIMARY KEY(app_id) -); - -INSERT INTO apps (app_id, created_at_time) - VALUES ('public', 0); - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS tenants ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - tenant_id VARCHAR(64) NOT NULL DEFAULT 'public', - created_at_time BIGINT , - CONSTRAINT tenants_pkey - PRIMARY KEY (app_id, tenant_id), - CONSTRAINT tenants_app_id_fkey FOREIGN KEY(app_id) - REFERENCES apps (app_id) ON DELETE CASCADE -); - -INSERT INTO tenants (app_id, tenant_id, created_at_time) - VALUES ('public', 'public', 0); - ------------------------------------------------------------- - -ALTER TABLE key_value - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE key_value - DROP CONSTRAINT key_value_pkey; - -ALTER TABLE key_value - ADD CONSTRAINT key_value_pkey - PRIMARY KEY (app_id, tenant_id, name); - -ALTER TABLE key_value - ADD CONSTRAINT key_value_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS app_id_to_user_id ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - user_id CHAR(36) NOT NULL, - recipe_id VARCHAR(128) NOT NULL, - CONSTRAINT app_id_to_user_id_pkey - PRIMARY KEY (app_id, user_id), - CONSTRAINT app_id_to_user_id_app_id_fkey - FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE -); - -INSERT INTO app_id_to_user_id (user_id, recipe_id) - SELECT user_id, recipe_id - FROM all_auth_recipe_users; - ------------------------------------------------------------- - -ALTER TABLE all_auth_recipe_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE all_auth_recipe_users - DROP CONSTRAINT all_auth_recipe_users_pkey CASCADE; - -ALTER TABLE all_auth_recipe_users - ADD CONSTRAINT all_auth_recipe_users_pkey - PRIMARY KEY (app_id, tenant_id, user_id); - -ALTER TABLE all_auth_recipe_users - ADD CONSTRAINT all_auth_recipe_users_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - -ALTER TABLE all_auth_recipe_users - 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; - -DROP INDEX all_auth_recipe_users_pagination_index; - -CREATE INDEX all_auth_recipe_users_pagination_index ON all_auth_recipe_users (time_joined DESC, user_id DESC, tenant_id DESC, app_id DESC); - --- Multitenancy - -CREATE TABLE IF NOT EXISTS tenant_configs ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - core_config TEXT, - email_password_enabled BOOLEAN, - passwordless_enabled BOOLEAN, - third_party_enabled BOOLEAN, - CONSTRAINT tenant_configs_pkey - PRIMARY KEY (connection_uri_domain, app_id, tenant_id) -); - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS tenant_thirdparty_providers ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - third_party_id VARCHAR(28) NOT NULL, - name VARCHAR(64), - authorization_endpoint TEXT, - authorization_endpoint_query_params TEXT, - token_endpoint TEXT, - token_endpoint_body_params TEXT, - user_info_endpoint TEXT, - user_info_endpoint_query_params TEXT, - user_info_endpoint_headers TEXT, - jwks_uri TEXT, - oidc_discovery_endpoint TEXT, - require_email BOOLEAN, - user_info_map_from_id_token_payload_user_id VARCHAR(64), - user_info_map_from_id_token_payload_email VARCHAR(64), - user_info_map_from_id_token_payload_email_verified VARCHAR(64), - user_info_map_from_user_info_endpoint_user_id VARCHAR(64), - user_info_map_from_user_info_endpoint_email VARCHAR(64), - user_info_map_from_user_info_endpoint_email_verified VARCHAR(64), - CONSTRAINT tenant_thirdparty_providers_pkey - PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id), - CONSTRAINT tenant_thirdparty_providers_tenant_id_fkey - FOREIGN KEY(connection_uri_domain, app_id, tenant_id) - REFERENCES tenant_configs (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE -); - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS tenant_thirdparty_provider_clients ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - third_party_id VARCHAR(28) NOT NULL, - client_type VARCHAR(64) NOT NULL DEFAULT '', - client_id VARCHAR(256) NOT NULL, - client_secret TEXT, - scope VARCHAR(128)[], - force_pkce BOOLEAN, - additional_config TEXT, - CONSTRAINT tenant_thirdparty_provider_clients_pkey - PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type), - CONSTRAINT tenant_thirdparty_provider_clients_third_party_id_fkey - FOREIGN KEY (connection_uri_domain, app_id, tenant_id, third_party_id) - REFERENCES tenant_thirdparty_providers (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE -); - --- Session - -ALTER TABLE session_info - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE session_info - DROP CONSTRAINT session_info_pkey CASCADE; - -ALTER TABLE session_info - ADD CONSTRAINT session_info_pkey - PRIMARY KEY (app_id, tenant_id, session_handle); - -ALTER TABLE session_info - ADD CONSTRAINT session_info_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - -CREATE INDEX session_expiry_index ON session_info (expires_at); - ------------------------------------------------------------- - -ALTER TABLE session_access_token_signing_keys - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE session_access_token_signing_keys - DROP CONSTRAINT session_access_token_signing_keys_pkey CASCADE; - -ALTER TABLE session_access_token_signing_keys - ADD CONSTRAINT session_access_token_signing_keys_pkey - PRIMARY KEY (app_id, created_at_time); - -ALTER TABLE session_access_token_signing_keys - ADD CONSTRAINT session_access_token_signing_keys_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - --- JWT - -ALTER TABLE jwt_signing_keys - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE jwt_signing_keys - DROP CONSTRAINT jwt_signing_keys_pkey CASCADE; - -ALTER TABLE jwt_signing_keys - ADD CONSTRAINT jwt_signing_keys_pkey - PRIMARY KEY (app_id, key_id); - -ALTER TABLE jwt_signing_keys - ADD CONSTRAINT jwt_signing_keys_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - --- EmailVerification - -ALTER TABLE emailverification_verified_emails - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE emailverification_verified_emails - DROP CONSTRAINT emailverification_verified_emails_pkey CASCADE; - -ALTER TABLE emailverification_verified_emails - ADD CONSTRAINT emailverification_verified_emails_pkey - PRIMARY KEY (app_id, user_id, email); - -ALTER TABLE emailverification_verified_emails - ADD CONSTRAINT emailverification_verified_emails_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -ALTER TABLE emailverification_tokens - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE emailverification_tokens - DROP CONSTRAINT emailverification_tokens_pkey CASCADE; - -ALTER TABLE emailverification_tokens - ADD CONSTRAINT emailverification_tokens_pkey - PRIMARY KEY (app_id, tenant_id, user_id, email, token); - -ALTER TABLE emailverification_tokens - ADD CONSTRAINT emailverification_tokens_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - - --- EmailPassword - -ALTER TABLE emailpassword_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE emailpassword_users - DROP CONSTRAINT emailpassword_users_pkey CASCADE; - -ALTER TABLE emailpassword_users - DROP CONSTRAINT emailpassword_users_email_key CASCADE; - -ALTER TABLE emailpassword_users - ADD CONSTRAINT emailpassword_users_pkey - PRIMARY KEY (app_id, user_id); - -ALTER TABLE emailpassword_users - 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; - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS emailpassword_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - email VARCHAR(256) NOT NULL, - CONSTRAINT emailpassword_user_to_tenant_email_key - UNIQUE (app_id, tenant_id, email), - CONSTRAINT emailpassword_user_to_tenant_pkey - PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT emailpassword_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 -); - -INSERT INTO emailpassword_user_to_tenant (user_id, email) - SELECT user_id, email FROM emailpassword_users; - ------------------------------------------------------------- - -ALTER TABLE emailpassword_pswd_reset_tokens - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE emailpassword_pswd_reset_tokens - DROP CONSTRAINT emailpassword_pswd_reset_tokens_pkey CASCADE; - -ALTER TABLE emailpassword_pswd_reset_tokens - 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 - FOREIGN KEY (app_id, user_id) - REFERENCES emailpassword_users (app_id, user_id) ON DELETE CASCADE; - --- Passwordless - -ALTER TABLE passwordless_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE passwordless_users - DROP CONSTRAINT passwordless_users_pkey CASCADE; - -ALTER TABLE passwordless_users - ADD CONSTRAINT passwordless_users_pkey - PRIMARY KEY (app_id, user_id); - -ALTER TABLE passwordless_users - DROP CONSTRAINT passwordless_users_email_key; - -ALTER TABLE passwordless_users - DROP CONSTRAINT passwordless_users_phone_number_key; - -ALTER TABLE passwordless_users - 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; - ------------------------------------------------------------- - -CREATE TABLE IF NOT EXISTS passwordless_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - email VARCHAR(256), - phone_number VARCHAR(256), - CONSTRAINT passwordless_user_to_tenant_email_key - UNIQUE (app_id, tenant_id, email), - CONSTRAINT passwordless_user_to_tenant_phone_number_key - UNIQUE (app_id, tenant_id, phone_number), - CONSTRAINT passwordless_user_to_tenant_pkey - PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT passwordless_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 -); - -INSERT INTO passwordless_user_to_tenant (user_id, email, phone_number) - SELECT user_id, email, phone_number FROM passwordless_users; - ------------------------------------------------------------- - -ALTER TABLE passwordless_devices - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE passwordless_devices - DROP CONSTRAINT passwordless_devices_pkey CASCADE; - -ALTER TABLE passwordless_devices - ADD CONSTRAINT passwordless_devices_pkey - PRIMARY KEY (app_id, tenant_id, device_id_hash); - -ALTER TABLE passwordless_devices - ADD CONSTRAINT passwordless_devices_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - -DROP INDEX passwordless_devices_email_index; - -CREATE INDEX passwordless_devices_email_index ON passwordless_devices (app_id, tenant_id, email); - -DROP INDEX passwordless_devices_phone_number_index; - -CREATE INDEX passwordless_devices_phone_number_index ON passwordless_devices (app_id, tenant_id, phone_number); - ------------------------------------------------------------- - -ALTER TABLE passwordless_codes - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE passwordless_codes - DROP CONSTRAINT passwordless_codes_pkey CASCADE; - -ALTER TABLE passwordless_codes - 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 - FOREIGN KEY (app_id, tenant_id, device_id_hash) - REFERENCES passwordless_devices (app_id, tenant_id, device_id_hash) ON DELETE CASCADE; - -ALTER TABLE passwordless_codes - DROP CONSTRAINT passwordless_codes_link_code_hash_key; - -ALTER TABLE passwordless_codes - ADD CONSTRAINT passwordless_codes_link_code_hash_key - UNIQUE (app_id, tenant_id, link_code_hash); - -DROP INDEX passwordless_codes_created_at_index; - -CREATE INDEX passwordless_codes_created_at_index ON passwordless_codes (app_id, tenant_id, created_at); - -DROP INDEX passwordless_codes_device_id_hash_index; -CREATE INDEX passwordless_codes_device_id_hash_index ON passwordless_codes (app_id, tenant_id, device_id_hash); - --- ThirdParty - -ALTER TABLE thirdparty_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; +1. Ensure that the core is already upgraded to version 5.0.0 (CDI version 2.21) +2. Stop the core instance(s) +3. Run the migration script -ALTER TABLE thirdparty_users - DROP CONSTRAINT thirdparty_users_pkey CASCADE; +
+ + If using PostgreSQL + + #### Run the following SQL script -ALTER TABLE thirdparty_users - DROP CONSTRAINT thirdparty_users_user_id_key CASCADE; + ```sql + -- General Tables -ALTER TABLE thirdparty_users - ADD CONSTRAINT thirdparty_users_pkey - PRIMARY KEY (app_id, user_id); + CREATE TABLE IF NOT EXISTS apps ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + created_at_time BIGINT, + CONSTRAINT apps_pkey PRIMARY KEY(app_id) + ); -ALTER TABLE thirdparty_users - 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; + INSERT INTO apps (app_id, created_at_time) + VALUES ('public', 0) ON CONFLICT DO NOTHING; -DROP INDEX IF EXISTS thirdparty_users_thirdparty_user_id_index; + ------------------------------------------------------------ -CREATE INDEX thirdparty_users_thirdparty_user_id_index ON thirdparty_users (app_id, third_party_id, third_party_user_id); + CREATE TABLE IF NOT EXISTS tenants ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + tenant_id VARCHAR(64) NOT NULL DEFAULT 'public', + created_at_time BIGINT , + CONSTRAINT tenants_pkey + PRIMARY KEY (app_id, tenant_id), + CONSTRAINT tenants_app_id_fkey FOREIGN KEY(app_id) + REFERENCES apps (app_id) ON DELETE CASCADE + ); -DROP INDEX IF EXISTS thirdparty_users_email_index; + INSERT INTO tenants (app_id, tenant_id, created_at_time) + VALUES ('public', 'public', 0) ON CONFLICT DO NOTHING; -CREATE INDEX thirdparty_users_email_index ON thirdparty_users (app_id, email); + CREATE INDEX IF NOT EXISTS tenants_app_id_index ON tenants (app_id); ------------------------------------------------------------- + ------------------------------------------------------------ -CREATE TABLE IF NOT EXISTS thirdparty_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - third_party_id VARCHAR(28) NOT NULL, - third_party_user_id VARCHAR(256) NOT NULL, - CONSTRAINT thirdparty_user_to_tenant_third_party_user_id_key - UNIQUE (app_id, tenant_id, third_party_id, third_party_user_id), - CONSTRAINT thirdparty_user_to_tenant_pkey - PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT thirdparty_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 -); + ALTER TABLE key_value + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; -INSERT INTO thirdparty_user_to_tenant (user_id, third_party_id, third_party_user_id) - SELECT user_id, third_party_id, third_party_user_id FROM thirdparty_users; + ALTER TABLE key_value + DROP CONSTRAINT key_value_pkey; + + ALTER TABLE key_value + 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 + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + CREATE INDEX IF NOT EXISTS key_value_tenant_id_index ON key_value (app_id, tenant_id); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS app_id_to_user_id ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + user_id CHAR(36) NOT NULL, + recipe_id VARCHAR(128) NOT NULL, + CONSTRAINT app_id_to_user_id_pkey + PRIMARY KEY (app_id, user_id), + CONSTRAINT app_id_to_user_id_app_id_fkey + FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE + ); + + 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; + + CREATE INDEX IF NOT EXISTS app_id_to_user_id_app_id_index ON app_id_to_user_id (app_id); + + ------------------------------------------------------------ + + ALTER TABLE all_auth_recipe_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE all_auth_recipe_users + DROP CONSTRAINT all_auth_recipe_users_pkey CASCADE; + + ALTER TABLE all_auth_recipe_users + 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 + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + ALTER TABLE all_auth_recipe_users + 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 + FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + DROP INDEX all_auth_recipe_users_pagination_index; + + CREATE INDEX all_auth_recipe_users_pagination_index ON all_auth_recipe_users (time_joined DESC, user_id DESC, tenant_id DESC, app_id DESC); + + CREATE INDEX IF NOT EXISTS all_auth_recipe_user_id_index ON all_auth_recipe_users (app_id, user_id); + + CREATE INDEX IF NOT EXISTS all_auth_recipe_tenant_id_index ON all_auth_recipe_users (app_id, tenant_id); + + -- Multitenancy + + CREATE TABLE IF NOT EXISTS tenant_configs ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + core_config TEXT, + email_password_enabled BOOLEAN, + passwordless_enabled BOOLEAN, + third_party_enabled BOOLEAN, + CONSTRAINT tenant_configs_pkey + PRIMARY KEY (connection_uri_domain, app_id, tenant_id) + ); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS tenant_thirdparty_providers ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + third_party_id VARCHAR(28) NOT NULL, + name VARCHAR(64), + authorization_endpoint TEXT, + authorization_endpoint_query_params TEXT, + token_endpoint TEXT, + token_endpoint_body_params TEXT, + user_info_endpoint TEXT, + user_info_endpoint_query_params TEXT, + user_info_endpoint_headers TEXT, + jwks_uri TEXT, + oidc_discovery_endpoint TEXT, + require_email BOOLEAN, + user_info_map_from_id_token_payload_user_id VARCHAR(64), + user_info_map_from_id_token_payload_email VARCHAR(64), + user_info_map_from_id_token_payload_email_verified VARCHAR(64), + user_info_map_from_user_info_endpoint_user_id VARCHAR(64), + user_info_map_from_user_info_endpoint_email VARCHAR(64), + user_info_map_from_user_info_endpoint_email_verified VARCHAR(64), + CONSTRAINT tenant_thirdparty_providers_pkey + PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id), + CONSTRAINT tenant_thirdparty_providers_tenant_id_fkey + FOREIGN KEY(connection_uri_domain, app_id, tenant_id) + REFERENCES tenant_configs (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE + ); + + CREATE INDEX IF NOT EXISTS tenant_thirdparty_providers_tenant_id_index ON tenant_thirdparty_providers (connection_uri_domain, app_id, tenant_id); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS tenant_thirdparty_provider_clients ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + third_party_id VARCHAR(28) NOT NULL, + client_type VARCHAR(64) NOT NULL DEFAULT '', + client_id VARCHAR(256) NOT NULL, + client_secret TEXT, + scope VARCHAR(128)[], + force_pkce BOOLEAN, + additional_config TEXT, + CONSTRAINT tenant_thirdparty_provider_clients_pkey + PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type), + CONSTRAINT tenant_thirdparty_provider_clients_third_party_id_fkey + FOREIGN KEY (connection_uri_domain, app_id, tenant_id, third_party_id) + REFERENCES tenant_thirdparty_providers (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE + ); --- UserIdMapping + CREATE INDEX IF NOT EXISTS tenant_thirdparty_provider_clients_third_party_id_index ON tenant_thirdparty_provider_clients (connection_uri_domain, app_id, tenant_id, third_party_id); -ALTER TABLE userid_mapping - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + -- Session -ALTER TABLE userid_mapping - DROP CONSTRAINT userid_mapping_pkey CASCADE; + ALTER TABLE session_info + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE userid_mapping - ADD CONSTRAINT userid_mapping_pkey - PRIMARY KEY (app_id, supertokens_user_id, external_user_id); + ALTER TABLE session_info + DROP CONSTRAINT session_info_pkey CASCADE; -ALTER TABLE userid_mapping - DROP CONSTRAINT userid_mapping_supertokens_user_id_key; + ALTER TABLE session_info + ADD CONSTRAINT session_info_pkey + PRIMARY KEY (app_id, tenant_id, session_handle); -ALTER TABLE userid_mapping - ADD CONSTRAINT userid_mapping_supertokens_user_id_key - UNIQUE (app_id, supertokens_user_id); + ALTER TABLE session_info + DROP CONSTRAINT IF EXISTS session_info_tenant_id_fkey; -ALTER TABLE userid_mapping - DROP CONSTRAINT userid_mapping_external_user_id_key; + ALTER TABLE session_info + ADD CONSTRAINT session_info_tenant_id_fkey + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; -ALTER TABLE userid_mapping - ADD CONSTRAINT userid_mapping_external_user_id_key - UNIQUE (app_id, external_user_id); + CREATE INDEX IF NOT EXISTS session_expiry_index ON session_info (expires_at); -ALTER TABLE userid_mapping - DROP CONSTRAINT IF EXISTS userid_mapping_supertokens_user_id_fkey; + CREATE INDEX IF NOT EXISTS session_info_tenant_id_index ON session_info (app_id, tenant_id); -ALTER TABLE userid_mapping - 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; + ------------------------------------------------------------ --- UserRoles + ALTER TABLE session_access_token_signing_keys + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE roles - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE session_access_token_signing_keys + DROP CONSTRAINT session_access_token_signing_keys_pkey CASCADE; -ALTER TABLE roles - DROP CONSTRAINT roles_pkey CASCADE; + ALTER TABLE session_access_token_signing_keys + ADD CONSTRAINT session_access_token_signing_keys_pkey + PRIMARY KEY (app_id, created_at_time); -ALTER TABLE roles - ADD CONSTRAINT roles_pkey - PRIMARY KEY (app_id, role); + ALTER TABLE session_access_token_signing_keys + DROP CONSTRAINT IF EXISTS session_access_token_signing_keys_app_id_fkey; -ALTER TABLE roles - ADD CONSTRAINT roles_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ALTER TABLE session_access_token_signing_keys + ADD CONSTRAINT session_access_token_signing_keys_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; ------------------------------------------------------------- + CREATE INDEX IF NOT EXISTS access_token_signing_keys_app_id_index ON session_access_token_signing_keys (app_id); -ALTER TABLE role_permissions - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + -- JWT + + ALTER TABLE jwt_signing_keys + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE jwt_signing_keys + DROP CONSTRAINT jwt_signing_keys_pkey CASCADE; -ALTER TABLE role_permissions - DROP CONSTRAINT role_permissions_pkey CASCADE; + ALTER TABLE jwt_signing_keys + ADD CONSTRAINT jwt_signing_keys_pkey + PRIMARY KEY (app_id, key_id); -ALTER TABLE role_permissions - ADD CONSTRAINT role_permissions_pkey - PRIMARY KEY (app_id, role, permission); + ALTER TABLE jwt_signing_keys + DROP CONSTRAINT IF EXISTS jwt_signing_keys_app_id_fkey; -ALTER TABLE role_permissions - DROP CONSTRAINT IF EXISTS role_permissions_role_fkey; + ALTER TABLE jwt_signing_keys + ADD CONSTRAINT jwt_signing_keys_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE role_permissions - ADD CONSTRAINT role_permissions_role_fkey - FOREIGN KEY (app_id, role) - REFERENCES roles (app_id, role) ON DELETE CASCADE; + CREATE INDEX IF NOT EXISTS jwt_signing_keys_app_id_index ON jwt_signing_keys (app_id); -DROP INDEX role_permissions_permission_index; + -- EmailVerification -CREATE INDEX role_permissions_permission_index ON role_permissions (app_id, permission); + ALTER TABLE emailverification_verified_emails + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; ------------------------------------------------------------- + ALTER TABLE emailverification_verified_emails + DROP CONSTRAINT emailverification_verified_emails_pkey CASCADE; -ALTER TABLE user_roles - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE emailverification_verified_emails + ADD CONSTRAINT emailverification_verified_emails_pkey + PRIMARY KEY (app_id, user_id, email); -ALTER TABLE user_roles - DROP CONSTRAINT user_roles_pkey CASCADE; + ALTER TABLE emailverification_verified_emails + DROP CONSTRAINT IF EXISTS emailverification_verified_emails_app_id_fkey; -ALTER TABLE user_roles - ADD CONSTRAINT user_roles_pkey - PRIMARY KEY (app_id, tenant_id, user_id, role); + ALTER TABLE emailverification_verified_emails + ADD CONSTRAINT emailverification_verified_emails_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE user_roles - ADD CONSTRAINT user_roles_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + CREATE INDEX IF NOT EXISTS emailverification_verified_emails_app_id_index ON emailverification_verified_emails (app_id); -ALTER TABLE user_roles - DROP CONSTRAINT IF EXISTS user_roles_role_fkey; + ------------------------------------------------------------ -ALTER TABLE user_roles - ADD CONSTRAINT user_roles_role_fkey - FOREIGN KEY (app_id, role) - REFERENCES roles (app_id, role) ON DELETE CASCADE; + ALTER TABLE emailverification_tokens + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; -DROP INDEX user_roles_role_index; + ALTER TABLE emailverification_tokens + DROP CONSTRAINT emailverification_tokens_pkey CASCADE; -CREATE INDEX user_roles_role_index ON user_roles (app_id, tenant_id, role); + ALTER TABLE emailverification_tokens + ADD CONSTRAINT emailverification_tokens_pkey + PRIMARY KEY (app_id, tenant_id, user_id, email, token); --- UserMetadata + ALTER TABLE emailverification_tokens + DROP CONSTRAINT IF EXISTS emailverification_tokens_tenant_id_fkey; -ALTER TABLE user_metadata - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE emailverification_tokens + ADD CONSTRAINT emailverification_tokens_tenant_id_fkey + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; -ALTER TABLE user_metadata - DROP CONSTRAINT user_metadata_pkey CASCADE; + CREATE INDEX IF NOT EXISTS emailverification_tokens_tenant_id_index ON emailverification_tokens (app_id, tenant_id); -ALTER TABLE user_metadata - ADD CONSTRAINT user_metadata_pkey - PRIMARY KEY (app_id, user_id); + -- EmailPassword -ALTER TABLE user_metadata - ADD CONSTRAINT user_metadata_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ALTER TABLE emailpassword_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; --- Dashboard + ALTER TABLE emailpassword_users + DROP CONSTRAINT emailpassword_users_pkey CASCADE; -ALTER TABLE dashboard_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE emailpassword_users + DROP CONSTRAINT IF EXISTS emailpassword_users_email_key CASCADE; -ALTER TABLE dashboard_users - DROP CONSTRAINT dashboard_users_pkey CASCADE; + ALTER TABLE emailpassword_users + ADD CONSTRAINT emailpassword_users_pkey + PRIMARY KEY (app_id, user_id); -ALTER TABLE dashboard_users - ADD CONSTRAINT dashboard_users_pkey - PRIMARY KEY (app_id, user_id); + ALTER TABLE emailpassword_users + DROP CONSTRAINT IF EXISTS emailpassword_users_user_id_fkey; -ALTER TABLE dashboard_users - DROP CONSTRAINT dashboard_users_email_key; + ALTER TABLE emailpassword_users + 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; -ALTER TABLE dashboard_users - ADD CONSTRAINT dashboard_users_email_key - UNIQUE (app_id, email); + ------------------------------------------------------------ -ALTER TABLE dashboard_users - ADD CONSTRAINT dashboard_users_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + CREATE TABLE IF NOT EXISTS emailpassword_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + email VARCHAR(256) NOT NULL, + CONSTRAINT emailpassword_user_to_tenant_email_key + UNIQUE (app_id, tenant_id, email), + CONSTRAINT emailpassword_user_to_tenant_pkey + PRIMARY KEY (app_id, tenant_id, user_id), + CONSTRAINT emailpassword_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 + ); ------------------------------------------------------------- + ALTER TABLE emailpassword_user_to_tenant + DROP CONSTRAINT IF EXISTS emailpassword_user_to_tenant_email_key; -ALTER TABLE dashboard_user_sessions - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE emailpassword_user_to_tenant + ADD CONSTRAINT emailpassword_user_to_tenant_email_key + UNIQUE (app_id, tenant_id, email); -ALTER TABLE dashboard_user_sessions - DROP CONSTRAINT dashboard_user_sessions_pkey CASCADE; + ALTER TABLE emailpassword_user_to_tenant + DROP CONSTRAINT IF EXISTS emailpassword_user_to_tenant_user_id_fkey; -ALTER TABLE dashboard_user_sessions - ADD CONSTRAINT dashboard_user_sessions_pkey - PRIMARY KEY (app_id, session_id); + ALTER TABLE emailpassword_user_to_tenant + ADD CONSTRAINT emailpassword_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; -ALTER TABLE dashboard_user_sessions - DROP CONSTRAINT IF EXISTS dashboard_user_sessions_user_id_fkey; + INSERT INTO emailpassword_user_to_tenant (user_id, email) + SELECT user_id, email FROM emailpassword_users ON CONFLICT DO NOTHING; -ALTER TABLE dashboard_user_sessions - ADD CONSTRAINT dashboard_user_sessions_user_id_fkey - FOREIGN KEY (app_id, user_id) - REFERENCES dashboard_users (app_id, user_id) ON DELETE CASCADE; + ------------------------------------------------------------ --- TOTP + ALTER TABLE emailpassword_pswd_reset_tokens + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE totp_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE emailpassword_pswd_reset_tokens + DROP CONSTRAINT emailpassword_pswd_reset_tokens_pkey CASCADE; -ALTER TABLE totp_users - DROP CONSTRAINT totp_users_pkey CASCADE; + ALTER TABLE emailpassword_pswd_reset_tokens + ADD CONSTRAINT emailpassword_pswd_reset_tokens_pkey + PRIMARY KEY (app_id, user_id, token); -ALTER TABLE totp_users - ADD CONSTRAINT totp_users_pkey - PRIMARY KEY (app_id, user_id); + ALTER TABLE emailpassword_pswd_reset_tokens + DROP CONSTRAINT IF EXISTS emailpassword_pswd_reset_tokens_user_id_fkey; -ALTER TABLE totp_users - ADD CONSTRAINT totp_users_app_id_fkey - FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ALTER TABLE emailpassword_pswd_reset_tokens + 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; ------------------------------------------------------------- + CREATE INDEX IF NOT EXISTS emailpassword_pswd_reset_tokens_user_id_index ON emailpassword_pswd_reset_tokens (app_id, user_id); -ALTER TABLE totp_user_devices - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + -- Passwordless -ALTER TABLE totp_user_devices - DROP CONSTRAINT totp_user_devices_pkey; + ALTER TABLE passwordless_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE totp_user_devices - ADD CONSTRAINT totp_user_devices_pkey - PRIMARY KEY (app_id, user_id, device_name); + ALTER TABLE passwordless_users + DROP CONSTRAINT passwordless_users_pkey CASCADE; -ALTER TABLE totp_user_devices - DROP CONSTRAINT IF EXISTS totp_user_devices_user_id_fkey; + ALTER TABLE passwordless_users + ADD CONSTRAINT passwordless_users_pkey + PRIMARY KEY (app_id, user_id); -ALTER TABLE totp_user_devices - ADD CONSTRAINT totp_user_devices_user_id_fkey - FOREIGN KEY (app_id, user_id) - REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE passwordless_users + DROP CONSTRAINT IF EXISTS passwordless_users_email_key; ------------------------------------------------------------- + ALTER TABLE passwordless_users + DROP CONSTRAINT IF EXISTS passwordless_users_phone_number_key; -ALTER TABLE totp_used_codes - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE passwordless_users + DROP CONSTRAINT IF EXISTS passwordless_users_user_id_fkey; -ALTER TABLE totp_used_codes - DROP CONSTRAINT totp_used_codes_pkey CASCADE; + ALTER TABLE passwordless_users + 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; -ALTER TABLE totp_used_codes - 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; + CREATE TABLE IF NOT EXISTS passwordless_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + email VARCHAR(256), + phone_number VARCHAR(256), + CONSTRAINT passwordless_user_to_tenant_email_key + UNIQUE (app_id, tenant_id, email), + CONSTRAINT passwordless_user_to_tenant_phone_number_key + UNIQUE (app_id, tenant_id, phone_number), + CONSTRAINT passwordless_user_to_tenant_pkey + PRIMARY KEY (app_id, tenant_id, user_id), + CONSTRAINT passwordless_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 + ); -ALTER TABLE totp_used_codes - ADD CONSTRAINT totp_used_codes_user_id_fkey - FOREIGN KEY (app_id, user_id) - REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE passwordless_user_to_tenant + DROP CONSTRAINT IF EXISTS passwordless_user_to_tenant_user_id_fkey; -ALTER TABLE totp_used_codes - ADD CONSTRAINT totp_used_codes_tenant_id_fkey - FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + ALTER TABLE passwordless_user_to_tenant + ADD CONSTRAINT passwordless_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; -DROP INDEX totp_used_codes_expiry_time_ms_index; + INSERT INTO passwordless_user_to_tenant (user_id, email, phone_number) + SELECT user_id, email, phone_number FROM passwordless_users ON CONFLICT DO NOTHING; -CREATE INDEX totp_used_codes_expiry_time_ms_index ON totp_used_codes (app_id, tenant_id, expiry_time_ms); + ------------------------------------------------------------ --- ActiveUsers + ALTER TABLE passwordless_devices + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE user_last_active - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE passwordless_devices + DROP CONSTRAINT passwordless_devices_pkey CASCADE; -ALTER TABLE user_last_active - DROP CONSTRAINT user_last_active_pkey CASCADE; + ALTER TABLE passwordless_devices + ADD CONSTRAINT passwordless_devices_pkey + PRIMARY KEY (app_id, tenant_id, device_id_hash); -ALTER TABLE user_last_active - ADD CONSTRAINT user_last_active_pkey - PRIMARY KEY (app_id, user_id); -``` + ALTER TABLE passwordless_devices + DROP CONSTRAINT IF EXISTS passwordless_devices_tenant_id_fkey; -
+ ALTER TABLE passwordless_devices + ADD CONSTRAINT passwordless_devices_tenant_id_fkey + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; -
+ DROP INDEX IF EXISTS passwordless_devices_email_index; -If using MySQL + CREATE INDEX IF NOT EXISTS passwordless_devices_email_index ON passwordless_devices (app_id, tenant_id, email); -#### Run the following SQL script + DROP INDEX IF EXISTS passwordless_devices_phone_number_index; -```sql --- Drop Foreign keys + CREATE INDEX IF NOT EXISTS passwordless_devices_phone_number_index ON passwordless_devices (app_id, tenant_id, phone_number); -ALTER TABLE emailpassword_pswd_reset_tokens - DROP FOREIGN KEY emailpassword_pswd_reset_tokens_ibfk_1; + CREATE INDEX IF NOT EXISTS passwordless_devices_tenant_id_index ON passwordless_devices (app_id, tenant_id); -ALTER TABLE passwordless_codes - DROP FOREIGN KEY passwordless_codes_ibfk_1; + ------------------------------------------------------------ -ALTER TABLE userid_mapping - DROP FOREIGN KEY userid_mapping_ibfk_1; + ALTER TABLE passwordless_codes + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE role_permissions - DROP FOREIGN KEY role_permissions_ibfk_1; + ALTER TABLE passwordless_codes + DROP CONSTRAINT passwordless_codes_pkey CASCADE; -ALTER TABLE user_roles - DROP FOREIGN KEY user_roles_ibfk_1; + ALTER TABLE passwordless_codes + ADD CONSTRAINT passwordless_codes_pkey + PRIMARY KEY (app_id, tenant_id, code_id); -ALTER TABLE dashboard_user_sessions - DROP FOREIGN KEY dashboard_user_sessions_ibfk_1; + ALTER TABLE passwordless_codes + DROP CONSTRAINT IF EXISTS passwordless_codes_device_id_hash_fkey; -ALTER TABLE totp_user_devices - DROP FOREIGN KEY totp_user_devices_ibfk_1; + ALTER TABLE passwordless_codes + 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; -ALTER TABLE totp_used_codes - DROP FOREIGN KEY totp_used_codes_ibfk_1; + ALTER TABLE passwordless_codes + DROP CONSTRAINT passwordless_codes_link_code_hash_key; --- General Tables + ALTER TABLE passwordless_codes + DROP CONSTRAINT IF EXISTS passwordless_codes_link_code_hash_key; -CREATE TABLE IF NOT EXISTS apps ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - created_at_time BIGINT UNSIGNED, - PRIMARY KEY(app_id) -); + ALTER TABLE passwordless_codes + ADD CONSTRAINT passwordless_codes_link_code_hash_key + UNIQUE (app_id, tenant_id, link_code_hash); -INSERT INTO apps (app_id, created_at_time) - VALUES ('public', 0); + DROP INDEX IF EXISTS passwordless_codes_created_at_index; ------------------------------------------------------------- + CREATE INDEX IF NOT EXISTS passwordless_codes_created_at_index ON passwordless_codes (app_id, tenant_id, created_at); -CREATE TABLE IF NOT EXISTS tenants ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - tenant_id VARCHAR(64) NOT NULL DEFAULT 'public', - created_at_time BIGINT UNSIGNED, - PRIMARY KEY (app_id, tenant_id), - FOREIGN KEY(app_id) - REFERENCES apps (app_id) ON DELETE CASCADE -); + DROP INDEX IF EXISTS passwordless_codes_device_id_hash_index; + CREATE INDEX IF NOT EXISTS passwordless_codes_device_id_hash_index ON passwordless_codes (app_id, tenant_id, device_id_hash); -INSERT INTO tenants (app_id, tenant_id, created_at_time) - VALUES ('public', 'public', 0); + -- ThirdParty ------------------------------------------------------------- + ALTER TABLE thirdparty_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE key_value - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE thirdparty_users + DROP CONSTRAINT thirdparty_users_pkey CASCADE; -ALTER TABLE key_value - DROP PRIMARY KEY; + ALTER TABLE thirdparty_users + DROP CONSTRAINT IF EXISTS thirdparty_users_user_id_key CASCADE; -ALTER TABLE key_value - ADD PRIMARY KEY (app_id, tenant_id, name); + ALTER TABLE thirdparty_users + ADD CONSTRAINT thirdparty_users_pkey + PRIMARY KEY (app_id, user_id); -ALTER TABLE key_value - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - --- CREATE INDEX key_value_tenant_id_index ON key_value (app_id, tenant_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 + FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; -CREATE TABLE IF NOT EXISTS app_id_to_user_id ( - app_id VARCHAR(64) NOT NULL DEFAULT 'public', - user_id CHAR(36) NOT NULL, - recipe_id VARCHAR(128) NOT NULL, - PRIMARY KEY (app_id, user_id), - FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE -); + DROP INDEX IF EXISTS thirdparty_users_thirdparty_user_id_index; -INSERT INTO app_id_to_user_id (user_id, recipe_id) - SELECT user_id, recipe_id - FROM all_auth_recipe_users; + CREATE INDEX IF NOT EXISTS thirdparty_users_thirdparty_user_id_index ON thirdparty_users (app_id, third_party_id, third_party_user_id); ------------------------------------------------------------- + DROP INDEX IF EXISTS thirdparty_users_email_index; -ALTER TABLE all_auth_recipe_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + CREATE INDEX IF NOT EXISTS thirdparty_users_email_index ON thirdparty_users (app_id, email); -ALTER TABLE all_auth_recipe_users - DROP PRIMARY KEY; + ------------------------------------------------------------ -ALTER TABLE all_auth_recipe_users - ADD PRIMARY KEY (app_id, tenant_id, user_id); + CREATE TABLE IF NOT EXISTS thirdparty_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + third_party_id VARCHAR(28) NOT NULL, + third_party_user_id VARCHAR(256) NOT NULL, + CONSTRAINT thirdparty_user_to_tenant_third_party_user_id_key + UNIQUE (app_id, tenant_id, third_party_id, third_party_user_id), + CONSTRAINT thirdparty_user_to_tenant_pkey + PRIMARY KEY (app_id, tenant_id, user_id), + CONSTRAINT thirdparty_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 + ); -ALTER TABLE all_auth_recipe_users - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + ALTER TABLE thirdparty_user_to_tenant + DROP CONSTRAINT IF EXISTS thirdparty_user_to_tenant_third_party_user_id_key; -ALTER TABLE all_auth_recipe_users - ADD FOREIGN KEY (app_id, user_id) - REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; - -ALTER TABLE all_auth_recipe_users - DROP INDEX all_auth_recipe_users_pagination_index; - -CREATE INDEX all_auth_recipe_users_pagination_index ON all_auth_recipe_users (time_joined DESC, user_id DESC, tenant_id DESC, app_id DESC); + ALTER TABLE thirdparty_user_to_tenant + ADD CONSTRAINT thirdparty_user_to_tenant_third_party_user_id_key + UNIQUE (app_id, tenant_id, third_party_id, third_party_user_id); --- Multitenancy + ALTER TABLE thirdparty_user_to_tenant + DROP CONSTRAINT IF EXISTS thirdparty_user_to_tenant_user_id_fkey; -CREATE TABLE IF NOT EXISTS tenant_configs ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - core_config TEXT, - email_password_enabled BOOLEAN, - passwordless_enabled BOOLEAN, - third_party_enabled BOOLEAN, - PRIMARY KEY (connection_uri_domain, app_id, tenant_id) -); - ------------------------------------------------------------- + ALTER TABLE thirdparty_user_to_tenant + ADD CONSTRAINT thirdparty_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; -CREATE TABLE IF NOT EXISTS tenant_thirdparty_providers ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - third_party_id VARCHAR(28) NOT NULL, - name VARCHAR(64), - authorization_endpoint TEXT, - authorization_endpoint_query_params TEXT, - token_endpoint TEXT, - token_endpoint_body_params TEXT, - user_info_endpoint TEXT, - user_info_endpoint_query_params TEXT, - user_info_endpoint_headers TEXT, - jwks_uri TEXT, - oidc_discovery_endpoint TEXT, - require_email BOOLEAN, - user_info_map_from_id_token_payload_user_id VARCHAR(64), - user_info_map_from_id_token_payload_email VARCHAR(64), - user_info_map_from_id_token_payload_email_verified VARCHAR(64), - user_info_map_from_user_info_endpoint_user_id VARCHAR(64), - user_info_map_from_user_info_endpoint_email VARCHAR(64), - user_info_map_from_user_info_endpoint_email_verified VARCHAR(64), - PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id), - FOREIGN KEY(connection_uri_domain, app_id, tenant_id) - REFERENCES tenant_configs (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE -); + INSERT INTO thirdparty_user_to_tenant (user_id, third_party_id, third_party_user_id) + SELECT user_id, third_party_id, third_party_user_id FROM thirdparty_users ON CONFLICT DO NOTHING; ------------------------------------------------------------- + -- UserIdMapping -CREATE TABLE IF NOT EXISTS tenant_thirdparty_provider_clients ( - connection_uri_domain VARCHAR(256) DEFAULT '', - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - third_party_id VARCHAR(28) NOT NULL, - client_type VARCHAR(64) NOT NULL DEFAULT '', - client_id VARCHAR(256) NOT NULL, - client_secret TEXT, - scope TEXT, - force_pkce BOOLEAN, - additional_config TEXT, - PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type), - FOREIGN KEY (connection_uri_domain, app_id, tenant_id, third_party_id) - REFERENCES tenant_thirdparty_providers (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE -); + ALTER TABLE userid_mapping + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE userid_mapping + DROP CONSTRAINT IF EXISTS userid_mapping_pkey CASCADE; --- Session + ALTER TABLE userid_mapping + ADD CONSTRAINT userid_mapping_pkey + PRIMARY KEY (app_id, supertokens_user_id, external_user_id); -ALTER TABLE session_info - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE userid_mapping + DROP CONSTRAINT IF EXISTS userid_mapping_supertokens_user_id_key; -ALTER TABLE session_info - DROP PRIMARY KEY; + ALTER TABLE userid_mapping + ADD CONSTRAINT userid_mapping_supertokens_user_id_key + UNIQUE (app_id, supertokens_user_id); -ALTER TABLE session_info - ADD PRIMARY KEY (app_id, tenant_id, session_handle); + ALTER TABLE userid_mapping + DROP CONSTRAINT IF EXISTS userid_mapping_external_user_id_key; -ALTER TABLE session_info - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + ALTER TABLE userid_mapping + ADD CONSTRAINT userid_mapping_external_user_id_key + UNIQUE (app_id, external_user_id); -CREATE INDEX session_expiry_index ON session_info (expires_at); + ALTER TABLE userid_mapping + DROP CONSTRAINT IF EXISTS userid_mapping_supertokens_user_id_fkey; ------------------------------------------------------------- + ALTER TABLE userid_mapping + 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; -ALTER TABLE session_access_token_signing_keys - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + CREATE INDEX IF NOT EXISTS userid_mapping_supertokens_user_id_index ON userid_mapping (app_id, supertokens_user_id); -ALTER TABLE session_access_token_signing_keys - DROP PRIMARY KEY; + -- UserRoles -ALTER TABLE session_access_token_signing_keys - ADD PRIMARY KEY (app_id, created_at_time); + ALTER TABLE roles + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE session_access_token_signing_keys - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ALTER TABLE roles + DROP CONSTRAINT roles_pkey CASCADE; --- JWT + ALTER TABLE roles + ADD CONSTRAINT roles_pkey + PRIMARY KEY (app_id, role); -ALTER TABLE jwt_signing_keys - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE roles + DROP CONSTRAINT IF EXISTS roles_app_id_fkey; -ALTER TABLE jwt_signing_keys - DROP PRIMARY KEY; + ALTER TABLE roles + ADD CONSTRAINT roles_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE jwt_signing_keys - ADD PRIMARY KEY (app_id, key_id); + CREATE INDEX IF NOT EXISTS roles_app_id_index ON roles (app_id); -ALTER TABLE jwt_signing_keys - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ------------------------------------------------------------ --- EmailVerification + ALTER TABLE role_permissions + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE emailverification_verified_emails - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE role_permissions + DROP CONSTRAINT role_permissions_pkey CASCADE; -ALTER TABLE emailverification_verified_emails - DROP PRIMARY KEY; + ALTER TABLE role_permissions + ADD CONSTRAINT role_permissions_pkey + PRIMARY KEY (app_id, role, permission); -ALTER TABLE emailverification_verified_emails - ADD PRIMARY KEY (app_id, user_id, email); + ALTER TABLE role_permissions + DROP CONSTRAINT IF EXISTS role_permissions_role_fkey; -ALTER TABLE emailverification_verified_emails - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; + ALTER TABLE role_permissions + ADD CONSTRAINT role_permissions_role_fkey + FOREIGN KEY (app_id, role) + REFERENCES roles (app_id, role) ON DELETE CASCADE; ------------------------------------------------------------- + DROP INDEX IF EXISTS role_permissions_permission_index; -ALTER TABLE emailverification_tokens - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + CREATE INDEX IF NOT EXISTS role_permissions_permission_index ON role_permissions (app_id, permission); -ALTER TABLE emailverification_tokens - DROP PRIMARY KEY; + CREATE INDEX IF NOT EXISTS role_permissions_role_index ON role_permissions (app_id, role); -ALTER TABLE emailverification_tokens - ADD PRIMARY KEY (app_id, tenant_id, user_id, email, token); + ------------------------------------------------------------ -ALTER TABLE emailverification_tokens - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + ALTER TABLE user_roles + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; --- EmailPassword + ALTER TABLE user_roles + DROP CONSTRAINT user_roles_pkey CASCADE; -ALTER TABLE emailpassword_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE user_roles + ADD CONSTRAINT user_roles_pkey + PRIMARY KEY (app_id, tenant_id, user_id, role); -ALTER TABLE emailpassword_users - DROP PRIMARY KEY; + ALTER TABLE user_roles + DROP CONSTRAINT IF EXISTS user_roles_tenant_id_fkey; -ALTER TABLE emailpassword_users - DROP INDEX email; + ALTER TABLE user_roles + ADD CONSTRAINT user_roles_tenant_id_fkey + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; -ALTER TABLE emailpassword_users - ADD PRIMARY KEY (app_id, user_id); + ALTER TABLE user_roles + DROP CONSTRAINT IF EXISTS user_roles_role_fkey; -ALTER TABLE emailpassword_users - ADD FOREIGN KEY (app_id, user_id) - REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE user_roles + ADD CONSTRAINT user_roles_role_fkey + FOREIGN KEY (app_id, role) + REFERENCES roles (app_id, role) ON DELETE CASCADE; --- ------------------------------------------------------------ + DROP INDEX IF EXISTS user_roles_role_index; -CREATE TABLE IF NOT EXISTS emailpassword_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - email VARCHAR(256) NOT NULL, - CONSTRAINT email - UNIQUE (app_id, tenant_id, email), - PRIMARY KEY (app_id, tenant_id, user_id), - CONSTRAINT FOREIGN KEY (app_id, tenant_id, user_id) - REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE -); + CREATE INDEX IF NOT EXISTS user_roles_role_index ON user_roles (app_id, tenant_id, role); -INSERT INTO emailpassword_user_to_tenant (user_id, email) - SELECT user_id, email FROM emailpassword_users; + CREATE INDEX IF NOT EXISTS user_roles_tenant_id_index ON user_roles (app_id, tenant_id); ------------------------------------------------------------- + CREATE INDEX IF NOT EXISTS user_roles_app_id_role_index ON user_roles (app_id, role); -ALTER TABLE emailpassword_pswd_reset_tokens - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + -- UserMetadata -ALTER TABLE emailpassword_pswd_reset_tokens - DROP PRIMARY KEY; + ALTER TABLE user_metadata + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE emailpassword_pswd_reset_tokens - ADD PRIMARY KEY (app_id, user_id, token); + ALTER TABLE user_metadata + DROP CONSTRAINT user_metadata_pkey CASCADE; -ALTER TABLE emailpassword_pswd_reset_tokens - ADD FOREIGN KEY (app_id, user_id) - REFERENCES emailpassword_users (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE user_metadata + ADD CONSTRAINT user_metadata_pkey + PRIMARY KEY (app_id, user_id); --- Passwordless + ALTER TABLE user_metadata + DROP CONSTRAINT IF EXISTS user_metadata_app_id_fkey; -ALTER TABLE passwordless_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE user_metadata + ADD CONSTRAINT user_metadata_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE passwordless_users - DROP PRIMARY KEY; + CREATE INDEX IF NOT EXISTS user_metadata_app_id_index ON user_metadata (app_id); -ALTER TABLE passwordless_users - ADD PRIMARY KEY (app_id, user_id); + -- Dashboard -ALTER TABLE passwordless_users - DROP INDEX email; + ALTER TABLE dashboard_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE passwordless_users - DROP INDEX phone_number; + ALTER TABLE dashboard_users + DROP CONSTRAINT dashboard_users_pkey CASCADE; -ALTER TABLE passwordless_users - ADD FOREIGN KEY (app_id, user_id) - REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE dashboard_users + ADD CONSTRAINT dashboard_users_pkey + PRIMARY KEY (app_id, user_id); ------------------------------------------------------------- + ALTER TABLE dashboard_users + DROP CONSTRAINT IF EXISTS dashboard_users_email_key; -CREATE TABLE IF NOT EXISTS passwordless_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - email VARCHAR(256), - phone_number VARCHAR(256), - CONSTRAINT email - UNIQUE (app_id, tenant_id, email), - CONSTRAINT phone_number - UNIQUE (app_id, tenant_id, phone_number), - PRIMARY KEY (app_id, tenant_id, user_id), - FOREIGN KEY (app_id, tenant_id, user_id) - REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE -); + ALTER TABLE dashboard_users + ADD CONSTRAINT dashboard_users_email_key + UNIQUE (app_id, email); -INSERT INTO passwordless_user_to_tenant (user_id, email, phone_number) - SELECT user_id, email, phone_number FROM passwordless_users; + ALTER TABLE dashboard_users + DROP CONSTRAINT IF EXISTS dashboard_users_app_id_fkey; ------------------------------------------------------------- + ALTER TABLE dashboard_users + ADD CONSTRAINT dashboard_users_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE passwordless_devices - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + CREATE INDEX IF NOT EXISTS dashboard_users_app_id_index ON dashboard_users (app_id); -ALTER TABLE passwordless_devices - DROP PRIMARY KEY; + ------------------------------------------------------------ -ALTER TABLE passwordless_devices - ADD PRIMARY KEY (app_id, tenant_id, device_id_hash); + ALTER TABLE dashboard_user_sessions + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE passwordless_devices - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + ALTER TABLE dashboard_user_sessions + DROP CONSTRAINT dashboard_user_sessions_pkey CASCADE; -ALTER TABLE passwordless_devices - DROP INDEX passwordless_devices_email_index; + ALTER TABLE dashboard_user_sessions + ADD CONSTRAINT dashboard_user_sessions_pkey + PRIMARY KEY (app_id, session_id); -CREATE INDEX passwordless_devices_email_index ON passwordless_devices (app_id, tenant_id, email); + ALTER TABLE dashboard_user_sessions + DROP CONSTRAINT IF EXISTS dashboard_user_sessions_user_id_fkey; -ALTER TABLE passwordless_devices - DROP INDEX passwordless_devices_phone_number_index; + ALTER TABLE dashboard_user_sessions + ADD CONSTRAINT dashboard_user_sessions_user_id_fkey + FOREIGN KEY (app_id, user_id) + REFERENCES dashboard_users (app_id, user_id) ON DELETE CASCADE; -CREATE INDEX passwordless_devices_phone_number_index ON passwordless_devices (app_id, tenant_id, phone_number); + CREATE INDEX IF NOT EXISTS dashboard_user_sessions_user_id_index ON dashboard_user_sessions (app_id, user_id); ------------------------------------------------------------- + -- TOTP -ALTER TABLE passwordless_codes - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE totp_users + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE passwordless_codes - DROP PRIMARY KEY; + ALTER TABLE totp_users + DROP CONSTRAINT totp_users_pkey CASCADE; -ALTER TABLE passwordless_codes - ADD PRIMARY KEY (app_id, tenant_id, code_id); + ALTER TABLE totp_users + ADD CONSTRAINT totp_users_pkey + PRIMARY KEY (app_id, user_id); -ALTER TABLE passwordless_codes - DROP INDEX device_id_hash; + ALTER TABLE totp_users + DROP CONSTRAINT IF EXISTS totp_users_app_id_fkey; -ALTER TABLE passwordless_codes - ADD FOREIGN KEY (app_id, tenant_id, device_id_hash) - REFERENCES passwordless_devices (app_id, tenant_id, device_id_hash) ON DELETE CASCADE; + ALTER TABLE totp_users + ADD CONSTRAINT totp_users_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; -ALTER TABLE passwordless_codes - DROP INDEX link_code_hash; + CREATE INDEX IF NOT EXISTS totp_users_app_id_index ON totp_users (app_id); -ALTER TABLE passwordless_codes - ADD CONSTRAINT link_code_hash - UNIQUE (app_id, tenant_id, link_code_hash); + ------------------------------------------------------------ -ALTER TABLE passwordless_codes - DROP INDEX passwordless_codes_created_at_index; + ALTER TABLE totp_user_devices + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -CREATE INDEX passwordless_codes_created_at_index ON passwordless_codes (app_id, tenant_id, created_at); + ALTER TABLE totp_user_devices + DROP CONSTRAINT totp_user_devices_pkey; --- ThirdParty + ALTER TABLE totp_user_devices + ADD CONSTRAINT totp_user_devices_pkey + PRIMARY KEY (app_id, user_id, device_name); -ALTER TABLE thirdparty_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + ALTER TABLE totp_user_devices + DROP CONSTRAINT IF EXISTS totp_user_devices_user_id_fkey; -ALTER TABLE thirdparty_users - DROP PRIMARY KEY; + ALTER TABLE totp_user_devices + ADD CONSTRAINT totp_user_devices_user_id_fkey + FOREIGN KEY (app_id, user_id) + REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; -ALTER TABLE thirdparty_users - DROP INDEX user_id; + CREATE INDEX IF NOT EXISTS totp_user_devices_user_id_index ON totp_user_devices (app_id, user_id); -ALTER TABLE thirdparty_users - ADD PRIMARY KEY (app_id, user_id); + ------------------------------------------------------------ -ALTER TABLE thirdparty_users - ADD FOREIGN KEY (app_id, user_id) - REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE totp_used_codes + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(64) DEFAULT 'public'; --- ALTER TABLE thirdparty_users --- DROP INDEX thirdparty_users_thirdparty_user_id_index; + ALTER TABLE totp_used_codes + DROP CONSTRAINT totp_used_codes_pkey CASCADE; -CREATE INDEX thirdparty_users_thirdparty_user_id_index ON thirdparty_users (app_id, third_party_id, third_party_user_id); + ALTER TABLE totp_used_codes + ADD CONSTRAINT totp_used_codes_pkey + PRIMARY KEY (app_id, tenant_id, user_id, created_time_ms); --- ALTER TABLE thirdparty_users --- DROP INDEX thirdparty_users_email_index; + ALTER TABLE totp_used_codes + DROP CONSTRAINT IF EXISTS totp_used_codes_user_id_fkey; -CREATE INDEX thirdparty_users_email_index ON thirdparty_users (app_id, email); + ALTER TABLE totp_used_codes + ADD CONSTRAINT totp_used_codes_user_id_fkey + FOREIGN KEY (app_id, user_id) + REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; ------------------------------------------------------------- + ALTER TABLE totp_used_codes + DROP CONSTRAINT IF EXISTS totp_used_codes_tenant_id_fkey; -CREATE TABLE IF NOT EXISTS thirdparty_user_to_tenant ( - app_id VARCHAR(64) DEFAULT 'public', - tenant_id VARCHAR(64) DEFAULT 'public', - user_id CHAR(36) NOT NULL, - third_party_id VARCHAR(28) NOT NULL, - third_party_user_id VARCHAR(256) NOT NULL, - CONSTRAINT third_party_user_id - UNIQUE (app_id, tenant_id, third_party_id, third_party_user_id), - PRIMARY KEY (app_id, tenant_id, user_id), - FOREIGN KEY (app_id, tenant_id, user_id) - REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE -); + ALTER TABLE totp_used_codes + ADD CONSTRAINT totp_used_codes_tenant_id_fkey + FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; -INSERT INTO thirdparty_user_to_tenant (user_id, third_party_id, third_party_user_id) - SELECT user_id, third_party_id, third_party_user_id FROM thirdparty_users; + DROP INDEX IF EXISTS totp_used_codes_expiry_time_ms_index; --- UserIdMapping + CREATE INDEX IF NOT EXISTS totp_used_codes_expiry_time_ms_index ON totp_used_codes (app_id, tenant_id, expiry_time_ms); -ALTER TABLE userid_mapping - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + CREATE INDEX IF NOT EXISTS totp_used_codes_user_id_index ON totp_used_codes (app_id, user_id); -ALTER TABLE userid_mapping - DROP PRIMARY KEY; + CREATE INDEX IF NOT EXISTS totp_used_codes_tenant_id_index ON totp_used_codes (app_id, tenant_id); -ALTER TABLE userid_mapping - ADD PRIMARY KEY (app_id, supertokens_user_id, external_user_id); + -- ActiveUsers -ALTER TABLE userid_mapping - DROP INDEX supertokens_user_id; + ALTER TABLE user_last_active + ADD COLUMN IF NOT EXISTS app_id VARCHAR(64) DEFAULT 'public'; -ALTER TABLE userid_mapping - ADD CONSTRAINT supertokens_user_id - UNIQUE (app_id, supertokens_user_id); + ALTER TABLE user_last_active + DROP CONSTRAINT user_last_active_pkey CASCADE; -ALTER TABLE userid_mapping - DROP INDEX external_user_id; + ALTER TABLE user_last_active + ADD CONSTRAINT user_last_active_pkey + PRIMARY KEY (app_id, user_id); -ALTER TABLE userid_mapping - ADD CONSTRAINT external_user_id - UNIQUE (app_id, external_user_id); + ALTER TABLE user_last_active + DROP CONSTRAINT IF EXISTS user_last_active_app_id_fkey; -ALTER TABLE userid_mapping - ADD FOREIGN KEY (app_id, supertokens_user_id) - REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + ALTER TABLE user_last_active + ADD CONSTRAINT user_last_active_app_id_fkey + FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; --- UserRoles + CREATE INDEX IF NOT EXISTS user_last_active_app_id_index ON user_last_active (app_id); -ALTER TABLE roles - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE roles - DROP PRIMARY KEY; - -ALTER TABLE roles - ADD PRIMARY KEY (app_id, role); - -ALTER TABLE roles - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -ALTER TABLE role_permissions - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE role_permissions - DROP PRIMARY KEY; - -ALTER TABLE role_permissions - ADD PRIMARY KEY (app_id, role, permission); - -ALTER TABLE role_permissions - ADD FOREIGN KEY (app_id, role) - REFERENCES roles (app_id, role) ON DELETE CASCADE; - -ALTER TABLE role_permissions - DROP INDEX role_permissions_permission_index; - -CREATE INDEX role_permissions_permission_index ON role_permissions (app_id, permission); - ------------------------------------------------------------- - -ALTER TABLE user_roles - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE user_roles - DROP PRIMARY KEY; - -ALTER TABLE user_roles - ADD PRIMARY KEY (app_id, tenant_id, user_id, role); - -ALTER TABLE user_roles - ADD FOREIGN KEY (app_id, role) - REFERENCES roles (app_id, role) ON DELETE CASCADE; - -ALTER TABLE user_roles - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - -ALTER TABLE user_roles - DROP INDEX user_roles_role_index; - -CREATE INDEX user_roles_role_index ON user_roles (app_id, tenant_id, role); - --- UserMetadata - -ALTER TABLE user_metadata - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE user_metadata - DROP PRIMARY KEY; - -ALTER TABLE user_metadata - ADD PRIMARY KEY (app_id, user_id); - -ALTER TABLE user_metadata - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - --- Dashboard - -ALTER TABLE dashboard_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE dashboard_users - DROP PRIMARY KEY; - -ALTER TABLE dashboard_users - ADD PRIMARY KEY (app_id, user_id); - -ALTER TABLE dashboard_users - DROP INDEX email; - -ALTER TABLE dashboard_users - ADD CONSTRAINT email - UNIQUE (app_id, email); - -ALTER TABLE dashboard_users - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -ALTER TABLE dashboard_user_sessions - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE dashboard_user_sessions - DROP PRIMARY KEY; - -ALTER TABLE dashboard_user_sessions - ADD PRIMARY KEY (app_id, session_id); - -ALTER TABLE dashboard_user_sessions - DROP INDEX user_id; - -ALTER TABLE dashboard_user_sessions - ADD FOREIGN KEY (app_id, user_id) - REFERENCES dashboard_users (app_id, user_id) ON DELETE CASCADE; - --- TOTP - -ALTER TABLE totp_users - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE totp_users - DROP PRIMARY KEY; - -ALTER TABLE totp_users - ADD PRIMARY KEY (app_id, user_id); - -ALTER TABLE totp_users - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -ALTER TABLE totp_user_devices - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE totp_user_devices - DROP PRIMARY KEY; - -ALTER TABLE totp_user_devices - ADD PRIMARY KEY (app_id, user_id, device_name); - -ALTER TABLE totp_user_devices - ADD FOREIGN KEY (app_id, user_id) - REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; - ------------------------------------------------------------- - -ALTER TABLE totp_used_codes - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', - ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE totp_used_codes - DROP PRIMARY KEY; - -ALTER TABLE totp_used_codes - ADD PRIMARY KEY (app_id, tenant_id, user_id, created_time_ms); - -ALTER TABLE totp_used_codes - ADD FOREIGN KEY (app_id, user_id) - REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; - -ALTER TABLE totp_used_codes - ADD FOREIGN KEY (app_id, tenant_id) - REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; - -ALTER TABLE totp_used_codes - DROP INDEX totp_used_codes_expiry_time_ms_index; - -CREATE INDEX totp_used_codes_expiry_time_ms_index ON totp_used_codes (app_id, tenant_id, expiry_time_ms); - --- ActiveUsers - -ALTER TABLE user_last_active - ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; - -ALTER TABLE user_last_active - DROP PRIMARY KEY; - -ALTER TABLE user_last_active - ADD PRIMARY KEY (app_id, user_id); - -ALTER TABLE user_last_active - ADD FOREIGN KEY (app_id) - REFERENCES apps (app_id) ON DELETE CASCADE; -``` + ``` + +
+ +
+ + If using MySQL + + #### Run the following SQL script + + ```sql + -- Drop Foreign keys + + ALTER TABLE emailpassword_pswd_reset_tokens + DROP FOREIGN KEY emailpassword_pswd_reset_tokens_ibfk_1; + + ALTER TABLE passwordless_codes + DROP FOREIGN KEY passwordless_codes_ibfk_1; + + ALTER TABLE userid_mapping + DROP FOREIGN KEY userid_mapping_ibfk_1; + + ALTER TABLE role_permissions + DROP FOREIGN KEY role_permissions_ibfk_1; + + ALTER TABLE user_roles + DROP FOREIGN KEY user_roles_ibfk_1; + + ALTER TABLE dashboard_user_sessions + DROP FOREIGN KEY dashboard_user_sessions_ibfk_1; + + ALTER TABLE totp_user_devices + DROP FOREIGN KEY totp_user_devices_ibfk_1; + + ALTER TABLE totp_used_codes + DROP FOREIGN KEY totp_used_codes_ibfk_1; + + -- General Tables + + CREATE TABLE IF NOT EXISTS apps ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + created_at_time BIGINT UNSIGNED, + PRIMARY KEY(app_id) + ); + + INSERT INTO apps (app_id, created_at_time) + VALUES ('public', 0); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS tenants ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + tenant_id VARCHAR(64) NOT NULL DEFAULT 'public', + created_at_time BIGINT UNSIGNED, + PRIMARY KEY (app_id, tenant_id), + FOREIGN KEY(app_id) + REFERENCES apps (app_id) ON DELETE CASCADE + ); + + INSERT INTO tenants (app_id, tenant_id, created_at_time) + VALUES ('public', 'public', 0); + + ------------------------------------------------------------ + + ALTER TABLE key_value + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE key_value + DROP PRIMARY KEY; + + ALTER TABLE key_value + ADD PRIMARY KEY (app_id, tenant_id, name); + + ALTER TABLE key_value + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + -- CREATE INDEX key_value_tenant_id_index ON key_value (app_id, tenant_id); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS app_id_to_user_id ( + app_id VARCHAR(64) NOT NULL DEFAULT 'public', + user_id CHAR(36) NOT NULL, + recipe_id VARCHAR(128) NOT NULL, + PRIMARY KEY (app_id, user_id), + FOREIGN KEY(app_id) REFERENCES apps (app_id) ON DELETE CASCADE + ); + + INSERT INTO app_id_to_user_id (user_id, recipe_id) + SELECT user_id, recipe_id + FROM all_auth_recipe_users; + + ------------------------------------------------------------ + + ALTER TABLE all_auth_recipe_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE all_auth_recipe_users + DROP PRIMARY KEY; + + ALTER TABLE all_auth_recipe_users + ADD PRIMARY KEY (app_id, tenant_id, user_id); + + ALTER TABLE all_auth_recipe_users + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + ALTER TABLE all_auth_recipe_users + ADD FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + ALTER TABLE all_auth_recipe_users + DROP INDEX all_auth_recipe_users_pagination_index; + + CREATE INDEX all_auth_recipe_users_pagination_index ON all_auth_recipe_users (time_joined DESC, user_id DESC, tenant_id DESC, app_id DESC); + + -- Multitenancy + + CREATE TABLE IF NOT EXISTS tenant_configs ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + core_config TEXT, + email_password_enabled BOOLEAN, + passwordless_enabled BOOLEAN, + third_party_enabled BOOLEAN, + PRIMARY KEY (connection_uri_domain, app_id, tenant_id) + ); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS tenant_thirdparty_providers ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + third_party_id VARCHAR(28) NOT NULL, + name VARCHAR(64), + authorization_endpoint TEXT, + authorization_endpoint_query_params TEXT, + token_endpoint TEXT, + token_endpoint_body_params TEXT, + user_info_endpoint TEXT, + user_info_endpoint_query_params TEXT, + user_info_endpoint_headers TEXT, + jwks_uri TEXT, + oidc_discovery_endpoint TEXT, + require_email BOOLEAN, + user_info_map_from_id_token_payload_user_id VARCHAR(64), + user_info_map_from_id_token_payload_email VARCHAR(64), + user_info_map_from_id_token_payload_email_verified VARCHAR(64), + user_info_map_from_user_info_endpoint_user_id VARCHAR(64), + user_info_map_from_user_info_endpoint_email VARCHAR(64), + user_info_map_from_user_info_endpoint_email_verified VARCHAR(64), + PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id), + FOREIGN KEY(connection_uri_domain, app_id, tenant_id) + REFERENCES tenant_configs (connection_uri_domain, app_id, tenant_id) ON DELETE CASCADE + ); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS tenant_thirdparty_provider_clients ( + connection_uri_domain VARCHAR(256) DEFAULT '', + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + third_party_id VARCHAR(28) NOT NULL, + client_type VARCHAR(64) NOT NULL DEFAULT '', + client_id VARCHAR(256) NOT NULL, + client_secret TEXT, + scope TEXT, + force_pkce BOOLEAN, + additional_config TEXT, + PRIMARY KEY (connection_uri_domain, app_id, tenant_id, third_party_id, client_type), + FOREIGN KEY (connection_uri_domain, app_id, tenant_id, third_party_id) + REFERENCES tenant_thirdparty_providers (connection_uri_domain, app_id, tenant_id, third_party_id) ON DELETE CASCADE + ); + + + -- Session + + ALTER TABLE session_info + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE session_info + DROP PRIMARY KEY; + + ALTER TABLE session_info + ADD PRIMARY KEY (app_id, tenant_id, session_handle); + + ALTER TABLE session_info + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + CREATE INDEX session_expiry_index ON session_info (expires_at); + + ------------------------------------------------------------ + + ALTER TABLE session_access_token_signing_keys + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE session_access_token_signing_keys + DROP PRIMARY KEY; + + ALTER TABLE session_access_token_signing_keys + ADD PRIMARY KEY (app_id, created_at_time); + + ALTER TABLE session_access_token_signing_keys + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + -- JWT + + ALTER TABLE jwt_signing_keys + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE jwt_signing_keys + DROP PRIMARY KEY; + + ALTER TABLE jwt_signing_keys + ADD PRIMARY KEY (app_id, key_id); + + ALTER TABLE jwt_signing_keys + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + -- EmailVerification + + ALTER TABLE emailverification_verified_emails + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE emailverification_verified_emails + DROP PRIMARY KEY; + + ALTER TABLE emailverification_verified_emails + ADD PRIMARY KEY (app_id, user_id, email); + + ALTER TABLE emailverification_verified_emails + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + ALTER TABLE emailverification_tokens + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE emailverification_tokens + DROP PRIMARY KEY; + + ALTER TABLE emailverification_tokens + ADD PRIMARY KEY (app_id, tenant_id, user_id, email, token); + + ALTER TABLE emailverification_tokens + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + -- EmailPassword + + ALTER TABLE emailpassword_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE emailpassword_users + DROP PRIMARY KEY; + + ALTER TABLE emailpassword_users + DROP INDEX email; + + ALTER TABLE emailpassword_users + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE emailpassword_users + ADD FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + -- ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS emailpassword_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + email VARCHAR(256) NOT NULL, + CONSTRAINT email + UNIQUE (app_id, tenant_id, email), + PRIMARY KEY (app_id, tenant_id, user_id), + CONSTRAINT FOREIGN KEY (app_id, tenant_id, user_id) + REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE + ); + + INSERT INTO emailpassword_user_to_tenant (user_id, email) + SELECT user_id, email FROM emailpassword_users; + + ------------------------------------------------------------ + + ALTER TABLE emailpassword_pswd_reset_tokens + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE emailpassword_pswd_reset_tokens + DROP PRIMARY KEY; + + ALTER TABLE emailpassword_pswd_reset_tokens + ADD PRIMARY KEY (app_id, user_id, token); + + ALTER TABLE emailpassword_pswd_reset_tokens + ADD FOREIGN KEY (app_id, user_id) + REFERENCES emailpassword_users (app_id, user_id) ON DELETE CASCADE; + + -- Passwordless + + ALTER TABLE passwordless_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE passwordless_users + DROP PRIMARY KEY; + + ALTER TABLE passwordless_users + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE passwordless_users + DROP INDEX email; + + ALTER TABLE passwordless_users + DROP INDEX phone_number; + + ALTER TABLE passwordless_users + ADD FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS passwordless_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + email VARCHAR(256), + phone_number VARCHAR(256), + CONSTRAINT email + UNIQUE (app_id, tenant_id, email), + CONSTRAINT phone_number + UNIQUE (app_id, tenant_id, phone_number), + PRIMARY KEY (app_id, tenant_id, user_id), + FOREIGN KEY (app_id, tenant_id, user_id) + REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE + ); + + INSERT INTO passwordless_user_to_tenant (user_id, email, phone_number) + SELECT user_id, email, phone_number FROM passwordless_users; + + ------------------------------------------------------------ + + ALTER TABLE passwordless_devices + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE passwordless_devices + DROP PRIMARY KEY; + + ALTER TABLE passwordless_devices + ADD PRIMARY KEY (app_id, tenant_id, device_id_hash); + + ALTER TABLE passwordless_devices + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + ALTER TABLE passwordless_devices + DROP INDEX passwordless_devices_email_index; + + CREATE INDEX passwordless_devices_email_index ON passwordless_devices (app_id, tenant_id, email); + + ALTER TABLE passwordless_devices + DROP INDEX passwordless_devices_phone_number_index; + + CREATE INDEX passwordless_devices_phone_number_index ON passwordless_devices (app_id, tenant_id, phone_number); + + ------------------------------------------------------------ + + ALTER TABLE passwordless_codes + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE passwordless_codes + DROP PRIMARY KEY; + + ALTER TABLE passwordless_codes + ADD PRIMARY KEY (app_id, tenant_id, code_id); + + ALTER TABLE passwordless_codes + DROP INDEX device_id_hash; + + ALTER TABLE passwordless_codes + ADD FOREIGN KEY (app_id, tenant_id, device_id_hash) + REFERENCES passwordless_devices (app_id, tenant_id, device_id_hash) ON DELETE CASCADE; + + ALTER TABLE passwordless_codes + DROP INDEX link_code_hash; + + ALTER TABLE passwordless_codes + ADD CONSTRAINT link_code_hash + UNIQUE (app_id, tenant_id, link_code_hash); + + ALTER TABLE passwordless_codes + DROP INDEX passwordless_codes_created_at_index; + + CREATE INDEX passwordless_codes_created_at_index ON passwordless_codes (app_id, tenant_id, created_at); + + -- ThirdParty + + ALTER TABLE thirdparty_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE thirdparty_users + DROP PRIMARY KEY; + + ALTER TABLE thirdparty_users + DROP INDEX user_id; + + ALTER TABLE thirdparty_users + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE thirdparty_users + ADD FOREIGN KEY (app_id, user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + -- ALTER TABLE thirdparty_users + -- DROP INDEX thirdparty_users_thirdparty_user_id_index; + + CREATE INDEX thirdparty_users_thirdparty_user_id_index ON thirdparty_users (app_id, third_party_id, third_party_user_id); + + -- ALTER TABLE thirdparty_users + -- DROP INDEX thirdparty_users_email_index; + + CREATE INDEX thirdparty_users_email_index ON thirdparty_users (app_id, email); + + ------------------------------------------------------------ + + CREATE TABLE IF NOT EXISTS thirdparty_user_to_tenant ( + app_id VARCHAR(64) DEFAULT 'public', + tenant_id VARCHAR(64) DEFAULT 'public', + user_id CHAR(36) NOT NULL, + third_party_id VARCHAR(28) NOT NULL, + third_party_user_id VARCHAR(256) NOT NULL, + CONSTRAINT third_party_user_id + UNIQUE (app_id, tenant_id, third_party_id, third_party_user_id), + PRIMARY KEY (app_id, tenant_id, user_id), + FOREIGN KEY (app_id, tenant_id, user_id) + REFERENCES all_auth_recipe_users (app_id, tenant_id, user_id) ON DELETE CASCADE + ); + + INSERT INTO thirdparty_user_to_tenant (user_id, third_party_id, third_party_user_id) + SELECT user_id, third_party_id, third_party_user_id FROM thirdparty_users; + + -- UserIdMapping + + ALTER TABLE userid_mapping + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE userid_mapping + DROP PRIMARY KEY; + + ALTER TABLE userid_mapping + ADD PRIMARY KEY (app_id, supertokens_user_id, external_user_id); + + ALTER TABLE userid_mapping + DROP INDEX supertokens_user_id; + + ALTER TABLE userid_mapping + ADD CONSTRAINT supertokens_user_id + UNIQUE (app_id, supertokens_user_id); + + ALTER TABLE userid_mapping + DROP INDEX external_user_id; + + ALTER TABLE userid_mapping + ADD CONSTRAINT external_user_id + UNIQUE (app_id, external_user_id); + + ALTER TABLE userid_mapping + ADD FOREIGN KEY (app_id, supertokens_user_id) + REFERENCES app_id_to_user_id (app_id, user_id) ON DELETE CASCADE; + + -- UserRoles + + ALTER TABLE roles + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE roles + DROP PRIMARY KEY; + + ALTER TABLE roles + ADD PRIMARY KEY (app_id, role); + + ALTER TABLE roles + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + ALTER TABLE role_permissions + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE role_permissions + DROP PRIMARY KEY; + + ALTER TABLE role_permissions + ADD PRIMARY KEY (app_id, role, permission); + + ALTER TABLE role_permissions + ADD FOREIGN KEY (app_id, role) + REFERENCES roles (app_id, role) ON DELETE CASCADE; + + ALTER TABLE role_permissions + DROP INDEX role_permissions_permission_index; + + CREATE INDEX role_permissions_permission_index ON role_permissions (app_id, permission); + + ------------------------------------------------------------ + + ALTER TABLE user_roles + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE user_roles + DROP PRIMARY KEY; + + ALTER TABLE user_roles + ADD PRIMARY KEY (app_id, tenant_id, user_id, role); + + ALTER TABLE user_roles + ADD FOREIGN KEY (app_id, role) + REFERENCES roles (app_id, role) ON DELETE CASCADE; + + ALTER TABLE user_roles + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + ALTER TABLE user_roles + DROP INDEX user_roles_role_index; + + CREATE INDEX user_roles_role_index ON user_roles (app_id, tenant_id, role); + + -- UserMetadata + + ALTER TABLE user_metadata + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE user_metadata + DROP PRIMARY KEY; + + ALTER TABLE user_metadata + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE user_metadata + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + -- Dashboard + + ALTER TABLE dashboard_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE dashboard_users + DROP PRIMARY KEY; + + ALTER TABLE dashboard_users + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE dashboard_users + DROP INDEX email; + + ALTER TABLE dashboard_users + ADD CONSTRAINT email + UNIQUE (app_id, email); + + ALTER TABLE dashboard_users + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + ALTER TABLE dashboard_user_sessions + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE dashboard_user_sessions + DROP PRIMARY KEY; + + ALTER TABLE dashboard_user_sessions + ADD PRIMARY KEY (app_id, session_id); + + ALTER TABLE dashboard_user_sessions + DROP INDEX user_id; + + ALTER TABLE dashboard_user_sessions + ADD FOREIGN KEY (app_id, user_id) + REFERENCES dashboard_users (app_id, user_id) ON DELETE CASCADE; + + -- TOTP + + ALTER TABLE totp_users + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE totp_users + DROP PRIMARY KEY; + + ALTER TABLE totp_users + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE totp_users + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + ALTER TABLE totp_user_devices + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE totp_user_devices + DROP PRIMARY KEY; + + ALTER TABLE totp_user_devices + ADD PRIMARY KEY (app_id, user_id, device_name); + + ALTER TABLE totp_user_devices + ADD FOREIGN KEY (app_id, user_id) + REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; + + ------------------------------------------------------------ + + ALTER TABLE totp_used_codes + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public', + ADD COLUMN tenant_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE totp_used_codes + DROP PRIMARY KEY; + + ALTER TABLE totp_used_codes + ADD PRIMARY KEY (app_id, tenant_id, user_id, created_time_ms); + + ALTER TABLE totp_used_codes + ADD FOREIGN KEY (app_id, user_id) + REFERENCES totp_users (app_id, user_id) ON DELETE CASCADE; + + ALTER TABLE totp_used_codes + ADD FOREIGN KEY (app_id, tenant_id) + REFERENCES tenants (app_id, tenant_id) ON DELETE CASCADE; + + ALTER TABLE totp_used_codes + DROP INDEX totp_used_codes_expiry_time_ms_index; + + CREATE INDEX totp_used_codes_expiry_time_ms_index ON totp_used_codes (app_id, tenant_id, expiry_time_ms); + + -- ActiveUsers + + ALTER TABLE user_last_active + ADD COLUMN app_id VARCHAR(64) DEFAULT 'public'; + + ALTER TABLE user_last_active + DROP PRIMARY KEY; + + ALTER TABLE user_last_active + ADD PRIMARY KEY (app_id, user_id); + + ALTER TABLE user_last_active + ADD FOREIGN KEY (app_id) + REFERENCES apps (app_id) ON DELETE CASCADE; + ``` + +
-
+4. Start the new instance(s) of the core (version 6.0.0) ## [5.0.0] - 2023-04-05 diff --git a/config.yaml b/config.yaml index a86039a8d..e65a47024 100644 --- a/config.yaml +++ b/config.yaml @@ -141,3 +141,7 @@ core_config_version: 0 # what database information is shown to / modifiable by the dev when they query the core to get the information about # their tenants. It only exposes that information when this key is used instead of the regular api_keys config. # supertokens_saas_secret: + +# (OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version when CDI version is not +# specified in the request. When set to null, the core will assume the latest version of the CDI. +# supertokens_default_cdi_version: diff --git a/devConfig.yaml b/devConfig.yaml index 78f7b79b8..f51d8b9f1 100644 --- a/devConfig.yaml +++ b/devConfig.yaml @@ -142,3 +142,7 @@ disable_telemetry: true # what database information is shown to / modifiable by the dev when they query the core to get the information about # their tenants. It only exposes that information when this key is used instead of the regular api_keys config. # supertokens_saas_secret: + +# (OPTIONAL | Default: null). This is used when the core needs to assume a specific CDI version when CDI version is not +# specified in the request. When set to null, the core will assume the latest version of the CDI. +# supertokens_default_cdi_version: diff --git a/src/main/java/io/supertokens/config/CoreConfig.java b/src/main/java/io/supertokens/config/CoreConfig.java index 52d599f1e..036416d41 100644 --- a/src/main/java/io/supertokens/config/CoreConfig.java +++ b/src/main/java/io/supertokens/config/CoreConfig.java @@ -28,6 +28,8 @@ import io.supertokens.exceptions.QuitProgramException; import io.supertokens.pluginInterface.LOG_LEVEL; import io.supertokens.pluginInterface.exceptions.InvalidConfigException; +import io.supertokens.utils.SemVer; +import io.supertokens.webserver.WebserverAPI; import org.apache.catalina.filters.RemoteAddrFilter; import org.jetbrains.annotations.TestOnly; @@ -148,6 +150,9 @@ public class CoreConfig { @JsonProperty private String supertokens_saas_secret = null; + @JsonProperty + private String supertokens_default_cdi_version = null; + private Set allowedLogLevels = null; public static Set getValidFields() { @@ -554,6 +559,18 @@ void validate(Main main) throws InvalidConfigException { } } } + + if (supertokens_default_cdi_version != null) { + try { + SemVer version = new SemVer(supertokens_default_cdi_version); + + if (!WebserverAPI.supportedVersions.contains(version)) { + throw new InvalidConfigException("supertokens_default_cdi_version is not a supported version"); + } + } catch (IllegalArgumentException e) { + throw new InvalidConfigException("supertokens_default_cdi_version is not a valid semantic version"); + } + } } public void createLoggingFile(Main main) throws IOException { @@ -636,6 +653,11 @@ static void assertThatCertainConfigIsNotSetForAppOrTenants(JsonObject config) th throw new InvalidConfigException( "supertokens_saas_secret can only be set via the core's base config setting"); } + + if (config.has("supertokens_default_cdi_version")) { + throw new InvalidConfigException( + "supertokens_default_cdi_version can only be set via the core's base config setting"); + } } void assertThatConfigFromSameAppIdAreNotConflicting(CoreConfig other) throws InvalidConfigException { @@ -718,5 +740,9 @@ void assertThatConfigFromSameAppIdAreNotConflicting(CoreConfig other) throws Inv } } } + + public String getDefaultCDIVersion() { + return this.supertokens_default_cdi_version; + } } diff --git a/src/main/java/io/supertokens/webserver/WebserverAPI.java b/src/main/java/io/supertokens/webserver/WebserverAPI.java index 1fc03a1d7..c579b2fa2 100644 --- a/src/main/java/io/supertokens/webserver/WebserverAPI.java +++ b/src/main/java/io/supertokens/webserver/WebserverAPI.java @@ -461,10 +461,17 @@ protected String getRIDFromRequest(HttpServletRequest req) { protected SemVer getVersionFromRequest(HttpServletRequest req) { String version = req.getHeader("cdi-version"); - if (version == null) { - return getLatestCDIVersion(); + + if (version != null) { + return new SemVer(version); } - return new SemVer(version); + + String defaultCDIVersion = Config.getBaseConfig(main).getDefaultCDIVersion(); + if (defaultCDIVersion != null) { + return new SemVer(defaultCDIVersion); + } + + return getLatestCDIVersion(); } public static class BadRequestException extends Exception { diff --git a/src/test/java/io/supertokens/test/CDIVersionTest.java b/src/test/java/io/supertokens/test/CDIVersionTest.java new file mode 100644 index 000000000..2b3bc717d --- /dev/null +++ b/src/test/java/io/supertokens/test/CDIVersionTest.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2023, 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; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.supertokens.ProcessState; +import io.supertokens.httpRequest.HttpRequest; +import io.supertokens.test.httpRequest.HttpRequestForTesting; +import io.supertokens.utils.SemVer; +import io.supertokens.webserver.Webserver; +import io.supertokens.webserver.WebserverAPI; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; + +import java.io.IOException; +import java.util.HashMap; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.*; + +public class CDIVersionTest { + @Rule + public TestRule watchman = Utils.getOnFailure(); + + @AfterClass + public static void afterTesting() { + Utils.afterTesting(); + } + + @Before + public void beforeEach() { + Utils.reset(); + } + + @Test + public void testThatAPIUsesLatestVersionByDefault() throws Exception { + String[] args = {"../"}; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/version-test"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + SemVer version = getVersionFromRequest(req); + + super.sendTextResponse(200, version.toString(), resp); + } + }); + + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null, + null, ""); + assertEquals(WebserverAPI.getLatestCDIVersion().toString(), response); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testThatAPIUsesVersionSpecifiedInTheRequest() throws Exception { + String[] args = {"../"}; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/version-test"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + SemVer version = getVersionFromRequest(req); + + super.sendTextResponse(200, version.toString(), resp); + } + }); + + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null, + "2.21", ""); + assertEquals("2.21", response); + + response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null, + "2.10", ""); + assertEquals("2.10", response); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testThatAPIUsesVersionSpecifiedInConfigAsDefault() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + Utils.setValueInConfig("supertokens_default_cdi_version", "2.21"); + process.startProcess(); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/version-test"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + SemVer version = getVersionFromRequest(req); + + super.sendTextResponse(200, version.toString(), resp); + } + }); + + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null, + null, ""); + assertEquals("2.21", response); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testThatAPIUsesVersionSpecifiedInRequestWhenTheConfigIsPresent() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + Utils.setValueInConfig("supertokens_default_cdi_version", "2.21"); + process.startProcess(); + + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + Webserver.getInstance(process.getProcess()).addAPI(new WebserverAPI(process.getProcess(), "") { + + private static final long serialVersionUID = 1L; + + @Override + public boolean checkAPIKey(HttpServletRequest req) { + return false; + } + + @Override + public String getPath() { + return "/version-test"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + SemVer version = getVersionFromRequest(req); + + super.sendTextResponse(200, version.toString(), resp); + } + }); + + String response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/version-test", new HashMap<>(), 1000, 1000, null, + "2.10", ""); + assertEquals("2.10", response); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testJWKSEndpointWorksInAllCases() throws Exception { + { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + { + // check regular output + JsonObject response = HttpRequest.sendGETRequest(process.getProcess(), "", "http://localhost:3567/.well-known/jwks.json", null, + 1000, 1000, null); + + assertEquals(response.entrySet().size(), 1); + + assertTrue(response.has("keys")); + JsonArray keys = response.get("keys").getAsJsonArray(); + assertEquals(keys.size(), 2); + } + + { + JsonObject oldResponse = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/recipe/jwt/jwks", null, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), + "jwt"); + + JsonArray oldKeys = oldResponse.getAsJsonArray("keys"); + assertEquals(oldKeys.size(), 2); // 1 static + 1 dynamic key + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + Utils.setValueInConfig("supertokens_default_cdi_version", "2.9"); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + { + // check regular output + JsonObject response = HttpRequest.sendGETRequest(process.getProcess(), "", "http://localhost:3567/.well-known/jwks.json", null, + 1000, 1000, null); + + assertEquals(response.entrySet().size(), 1); + + assertTrue(response.has("keys")); + JsonArray keys = response.get("keys").getAsJsonArray(); + assertEquals(keys.size(), 2); + } + + { + JsonObject oldResponse = HttpRequestForTesting.sendGETRequest(process.getProcess(), "", + "http://localhost:3567/recipe/jwt/jwks", null, 1000, 1000, null, Utils.getCdiVersionStringLatestForTests(), + "jwt"); + + JsonArray oldKeys = oldResponse.getAsJsonArray("keys"); + assertEquals(oldKeys.size(), 2); // 1 static + 1 dynamic key + } + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + } + + @Test + public void testInvalidSemanticVersion() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + Utils.setValueInConfig("supertokens_default_cdi_version", "2.x"); + process.startProcess(); + + ProcessState.EventAndException state = process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.INIT_FAILURE); + assertNotNull(state); + + assertEquals("supertokens_default_cdi_version is not a valid semantic version", state.exception.getCause().getMessage()); + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testUnsupportedVersion() throws Exception { + String[] args = {"../"}; + + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + Utils.setValueInConfig("supertokens_default_cdi_version", "2.1"); + process.startProcess(); + + ProcessState.EventAndException state = process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.INIT_FAILURE); + assertNotNull(state); + + assertEquals("supertokens_default_cdi_version is not a supported version", state.exception.getCause().getMessage()); + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } +} diff --git a/src/test/java/io/supertokens/test/multitenant/api/TestTenantIdIsNotPresentForOlderCDI.java b/src/test/java/io/supertokens/test/multitenant/api/TestTenantIdIsNotPresentForOlderCDI.java index 023c09086..3bfc81caf 100644 --- a/src/test/java/io/supertokens/test/multitenant/api/TestTenantIdIsNotPresentForOlderCDI.java +++ b/src/test/java/io/supertokens/test/multitenant/api/TestTenantIdIsNotPresentForOlderCDI.java @@ -341,7 +341,7 @@ public static JsonObject listUsers(TenantIdentifier sourceTenant, String paginat } JsonObject response = HttpRequestForTesting.sendGETRequest(main, "", HttpRequestForTesting.getMultitenantUrl(sourceTenant, "/users"), - params, 1000000, 1000000, null, + params, 1000, 1000, null, SemVer.v2_21.get(), null); assertEquals("OK", response.getAsJsonPrimitive("status").getAsString());