Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d9e1736
feat: adding new access token version and BE controlled dynamic/stati…
porcellus Jan 30, 2023
9242210
Merge remote-tracking branch 'origin/master' into feat/access_token_t…
porcellus Jan 30, 2023
1dbd0f2
feat: finishing jwt-to-access token + tests
porcellus Feb 13, 2023
910c96c
refactor: adding/using a semver class instead of version strings
porcellus Mar 1, 2023
9e9e2a6
Merge branch 'refactor/semver' into feat/access_token_to_jwt
porcellus Mar 1, 2023
dce2a2d
refactor: update/fix cdi version handling
porcellus Mar 2, 2023
3f77bee
refactor: adding/using a semver class instead of version strings (#576)
porcellus Mar 8, 2023
d241599
Merge remote-tracking branch 'origin/feat/access_token_to_jwt_base' i…
porcellus Mar 8, 2023
d2257b9
refactor: fix review comments
porcellus Mar 8, 2023
1db1e09
refactor: remove unused constructor
porcellus Mar 10, 2023
7449c52
feat: add checkDatabase to session verification API
porcellus Mar 13, 2023
639241c
feat: add an overlap time to generate dynamic signing keys before use
porcellus Mar 13, 2023
4ac24bd
docs: update comments based on review feedback
porcellus Mar 13, 2023
21e96f7
chore: update plugin interface version
porcellus Mar 13, 2023
58c0c8f
test: fix tests
porcellus Mar 14, 2023
64dc3c2
chore: update changelog
porcellus Mar 14, 2023
659c3a5
chore: add deprecation notice
porcellus Mar 14, 2023
e602fa2
fix: remove unused code
porcellus Mar 14, 2023
6e475ad
refactor: fix review comments
porcellus Mar 16, 2023
955f627
chore: update changelog
porcellus Mar 17, 2023
7215cf3
fix: add NOT NULL to use_static_key for in-memory db as well
porcellus Mar 17, 2023
2a2eea3
chore: fix table name in migration instructions in the changelog
porcellus Mar 19, 2023
aa0117e
Merge pull request #566 from supertokens/feat/access_token_to_jwt
porcellus Mar 19, 2023
e6e0cce
feat: rename useStaticSigningKey param and expand testing (#588)
porcellus Mar 22, 2023
2fea120
feat: make refresh api return unauthorised on AccessTokenPayloadError…
porcellus Mar 23, 2023
fba32d0
fix: minor consistency fixes (#617)
porcellus Apr 3, 2023
9bb1e30
refactor: update CDI version number
porcellus Apr 4, 2023
4381427
Merge remote-tracking branch 'origin/master' into feat/access_token_t…
porcellus Apr 4, 2023
321bbfe
fix: fix getting jwt signing keys with mongodb (#623)
porcellus Apr 5, 2023
c1beecf
test: update tests after merge
porcellus Apr 5, 2023
21e6f38
feat: make old config name still work for backwards compatibility (ma…
porcellus Apr 5, 2023
dd77680
refactor: update CDI version
porcellus Apr 5, 2023
640d7f0
chore: update version number
porcellus Apr 5, 2023
af5aec9
test: remove some checks that are no longer correct
porcellus Apr 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,127 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [unreleased]

## [5.0.0] - 2023-04-05

### Fixes

- Fixed creating JWTs using MongoDB if a key already exists

### Breaking changes

- Using an internal `SemVer` class to handle version numbers. This will make handling CDI version ranges easier.
- Support for CDI version `2.21`
- Removed POST `/recipe/handshake`
- Added `useDynamicSigningKey` into `createNewSession` (POST `/recipe/session`), replacing
`access_token_signing_key_dynamic` used in CDI<=2.18
- Added `useStaticSigningKey` into `createSignedJWT` (POST `/recipe/jwt`)
- Added `checkDatabase` into `verifySession` (POST `/recipe/session/verify`), replacing
`access_token_blacklisting` used in CDI<=2.18
- Removed `idRefreshToken`, `jwtSigningPublicKey`, `jwtSigningPublicKeyExpiryTime` and `jwtSigningPublicKeyList`
from responses
- Deprecated GET `/recipe/jwt/jwks`
- Added GET `/.well-known/jwks.json`: a standard jwks
- Added new access token version
- Uses standard prop names (i.e.: `sub` instead of `userId`)
- Contains the id of the signing key in the header (as `kid`)
- Stores the user payload merged into the root level, instead of the `userData` prop
- Session handling function now throw if the user payload contains protected props (`sub`, `iat`, `exp`,
`sessionHandle`, `refreshTokenHash1`, `parentRefreshTokenHash1`, `antiCsrfToken`)
- A related exception type was added as `AccessTokenPayloadError`
- Refactored the handling of signing keys
- `createNewSession` now takes a `useStaticKey` parameter instead of depending on the
`access_token_signing_key_dynamic` config value
- `createJWTToken` now supports signing by a dynamic key
- `getSession` now takes a `checkDatabase` parameter instead of using the `access_token_blacklisting` config value
- Updated plugin interface version to 2.21

### Configuration Changes

- `access_token_signing_key_dynamic` is now deprecated, only used for requests with CDI<=2.18
- `access_token_blacklisting` is now deprecated, only used for requests with CDI<=2.18
- Renamed `access_token_signing_key_update_interval` to `access_token_dynamic_signing_key_update_interval`

### Database Changes

- Added new `useStaticKey` field into session info
- Manual migration is also required if `access_token_signing_key_dynamic` was set to true

#### Migration steps for SQL
- If using `access_token_signing_key_dynamic` false:
- `ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(true);`
- ```sql
INSERT INTO jwt_signing_keys(key_id, key_string, algorithm, created_at)
select CONCAT('s-', created_at_time) as key_id, value as key_string, 'RS256' as algorithm, created_at_time as created_at
from session_access_token_signing_keys;
```
- If using `access_token_signing_key_dynamic` true:
- `ALTER TABLE session_info ADD COLUMN use_static_key BOOLEAN NOT NULL DEFAULT(false);`

#### Migration steps for MongoDB

- If using `access_token_signing_key_dynamic` false:
- ```
db.session_info.update({},
{
"$set": {
"use_static_key": true
}
});
```
- ```
db.key_value.aggregate([
{
"$match": {
_id: "access_token_signing_key_list"
}
},
{
$unwind: "$keys"
},
{
$addFields: {
_id: {
"$concat": [
"s-",
{
$convert: {
input: "$keys.created_at_time",
to: "string"
}
}
]
},
"key_string": "$keys.value",
"algorithm": "RS256",
"created_at": "$keys.created_at_time",

}
},
{
"$project": {
"keys": 0,

}
},
{
"$merge": {
"into": "jwt_signing_keys",

}
}
]);
```

- If using `access_token_signing_key_dynamic` true:
- ```
db.session_info.update({},
{
"$set": {
"use_static_key": false
}
});
```

## [4.6.0] - 2023-03-30

- Add Optional Search Tags to Pagination API to enable dashboard search
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
// }
//}

version = "4.6.0"
version = "5.0.0"


repositories {
Expand Down
15 changes: 7 additions & 8 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,19 @@ core_config_version: 0
# access_token_validity:


# (OPTIONAL | Default: false) boolean value. If true, allows for immediate revocation of any access token.
# Keep in mind that setting this to true will result in a db query for each API call that
# requires authentication.
# (OPTIONAL | Default: false) boolean value. Deprecated, please see changelog. Only used in CDI<=2.18
# If true, allows for immediate revocation of any access token. Keep in mind that setting this to true will result
# in a db query for each API call that requires authentication.
# access_token_blacklisting:


# (OPTIONAL | Default: true) boolean value. If this is set to true, the JWT (access token)
# signing key will change every fixed intervale of time.
# (OPTIONAL | Default: true) boolean value. Deprecated, please see changelog.
# If this is set to true, the access tokens created using CDI<=2.18 will be signed using a static signing key.
# access_token_signing_key_dynamic:


# (OPTIONAL | Default:168) integer value. Time in hours for how frequently the JWT (access token) signing key
# will change. This value only makes sense if "access_token_signing_key_dynamic" is true.
# access_token_signing_key_update_interval:
# (OPTIONAL | Default:168) integer value. Time in hours for how frequently the dynamic signing key will change.
# access_token_dynamic_signing_key_update_interval:


# (OPTIONAL | Default: 144000) double value. Time in mins for how long a refresh token is valid for.
Expand Down
3 changes: 2 additions & 1 deletion coreDriverInterfaceSupported.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"2.17",
"2.18",
"2.19",
"2.20"
"2.20",
"2.21"
]
}
17 changes: 9 additions & 8 deletions devConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,22 @@ core_config_version: 0
# access_token_validity:


# (OPTIONAL | Default: false) boolean value. If true, allows for immediate revocation of any access token.
# Keep in mind that setting this to true will result in a db query for each API call that
# requires authentication.
# (OPTIONAL | Default: false) boolean value. Deprecated, please see changelog. Only used in CDI<=2.18
# If true, allows for immediate revocation of any access token. Keep in mind that setting this to true will result
# in a db query for each API call that requires authentication.
# access_token_blacklisting:


# (OPTIONAL | Default: true) boolean value. If this is set to true, the JWT (access token)
# signing key will change every fixed intervale of time.
# (OPTIONAL | Default: true) boolean value. Deprecated, please see changelog.
# If this is set to true, the access tokens created using CDI<=2.18 will be signed using a static signing key.
# access_token_signing_key_dynamic:


# (OPTIONAL | Default:168) integer value. Time in hours for how frequently the JWT (access token) signing key
# will change. This value only makes sense if "access_token_signing_key_dynamic" is true.
# access_token_signing_key_update_interval:
# (OPTIONAL | Default:168) integer value. Time in hours for how frequently the dynamic signing key will change.
# access_token_dynamic_signing_key_update_interval:

# This is now deprecated, we only add this to the dev config to test if the fallback in the config parser works right
# access_token_signing_key_update_interval:

# (OPTIONAL | Default: 144000) double value. Time in mins for how long a refresh token is valid for.
# refresh_token_validity:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void testDeletingLicenseKeyWhenItIsNotSet() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonDELETERequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(1, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());

Expand Down Expand Up @@ -83,7 +83,7 @@ public void testDeletingLicenseKey() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonDELETERequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(1, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void testRetrievingFeatureFlagInfoWhenNoLicenseKeyIsSet() throws Exceptio

JsonObject response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/ee/featureflag",
null, 1000, 1000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 1000, 1000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(3, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());
assertEquals(0, response.get("features").getAsJsonArray().size());
Expand Down Expand Up @@ -77,7 +77,7 @@ public void testRetrievingFeatureFlagInfoWhenLicenseKeyIsSet() throws Exception

JsonObject response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/ee/featureflag",
null, 1000, 1000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 1000, 1000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(3, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());
assertEquals(1, response.get("features").getAsJsonArray().size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void testRetrievingLicenseKeyWhenItIsNotSet() throws Exception {

JsonObject response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
Assert.assertEquals(1, response.entrySet().size());
Assert.assertEquals("NO_LICENSE_KEY_FOUND_ERROR", response.get("status").getAsString());

Expand All @@ -64,7 +64,7 @@ public void testRetrievingLicenseKeyWhenItIsSet() throws Exception {
// retrieve license key
JsonObject response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");

assertEquals(2, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());
Expand Down Expand Up @@ -93,7 +93,7 @@ public void testRetrievingLicenseKeyWhenEEFolderDoesNotExist() throws Exception
// retrieve license key
JsonObject response = HttpRequestForTesting.sendGETRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
null, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");

Assert.assertEquals(1, response.entrySet().size());
Assert.assertEquals("NO_LICENSE_KEY_FOUND_ERROR", response.get("status").getAsString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void testSettingBadInput() throws Exception {
try {
HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
throw new Exception("should never come here");
} catch (HttpResponseException e) {
assertTrue(e.statusCode == 400 && e.getMessage().equals(
Expand Down Expand Up @@ -91,7 +91,7 @@ public void testSettingLicenseKeyWhenEEFolderDoesNotExist() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(1, response.entrySet().size());
assertEquals("MISSING_EE_FOLDER_ERROR", response.get("status").getAsString());

Expand All @@ -110,7 +110,7 @@ public void testSettingLicenseKeySuccessfully() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(1, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());

Expand Down Expand Up @@ -138,7 +138,7 @@ public void testCallingAPIToSyncLicenseKey() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
new JsonObject(), 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
new JsonObject(), 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");
assertEquals(1, response.entrySet().size());
assertEquals("OK", response.get("status").getAsString());

Expand All @@ -163,7 +163,7 @@ public void testSettingInvalidLicenseKey() throws Exception {

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(process.getProcess(), "",
"http://localhost:3567/ee/license",
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion(), "");
requestBody, 10000, 10000, null, WebserverAPI.getLatestCDIVersion().get(), "");

assertEquals(1, response.entrySet().size());
assertEquals("INVALID_LICENSE_KEY_ERROR", response.get("status").getAsString());
Expand Down
2 changes: 1 addition & 1 deletion pluginInterfaceSupported.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"_comment": "contains a list of plugin interfaces branch names that this core supports",
"versions": [
"2.22"
"2.23"
]
}
10 changes: 5 additions & 5 deletions src/main/java/io/supertokens/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@
import io.supertokens.exceptions.QuitProgramException;
import io.supertokens.featureflag.FeatureFlag;
import io.supertokens.inmemorydb.Start;
import io.supertokens.jwt.JWTSigningKey;
import io.supertokens.signingkeys.JWTSigningKey;
import io.supertokens.output.Logging;
import io.supertokens.pluginInterface.STORAGE_TYPE;
import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.session.accessToken.AccessTokenSigningKey;
import io.supertokens.signingkeys.AccessTokenSigningKey;
import io.supertokens.session.refreshToken.RefreshTokenKey;
import io.supertokens.signingkeys.SigningKeys;
import io.supertokens.storageLayer.StorageLayer;
import io.supertokens.version.Version;
import io.supertokens.webserver.Webserver;
Expand Down Expand Up @@ -193,6 +194,7 @@ private void init() throws IOException {
AccessTokenSigningKey.init(this);
RefreshTokenKey.init(this);
JWTSigningKey.init(this);
SigningKeys.init(this);

// starts removing old session cronjob
Cronjobs.addCronjob(this, DeleteExpiredSessions.getInstance(this));
Expand All @@ -218,9 +220,7 @@ private void init() throws IOException {
}

// starts DeleteExpiredAccessTokenSigningKeys cronjob if the access token signing keys can change
if (Config.getConfig(this).getAccessTokenSigningKeyDynamic()) {
Cronjobs.addCronjob(this, DeleteExpiredAccessTokenSigningKeys.getInstance(this));
}
Cronjobs.addCronjob(this, DeleteExpiredAccessTokenSigningKeys.getInstance(this));

// creates password hashing pool
PasswordHashing.init(this);
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/io/supertokens/ProcessState.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ public synchronized void clear() {
/**
* INIT: Initialization started INIT_FAILURE: Initialization failed
* STARTED: Initialized successfully SHUTTING_DOWN: Shut down signal received STOPPED
* RETRYING_ACCESS_TOKEN_JWT_VERIFICATION: When access
* token verification fails due to change in signing key, so we retry it
* RETRYING_ACCESS_TOKEN_JWT_VERIFICATION: When access token verification fails due to change in signing key, so we retry it
* CRON_TASK_ERROR_LOGGING: When an exception is thrown from a Cronjob
* DEVICE_DRIVER_INFO_LOGGED:When program is saving deviceDriverInfo into ping
* SERVER_PING: When program is pinging the server with information
Expand All @@ -81,7 +80,7 @@ public synchronized void clear() {
public enum PROCESS_STATE {
INIT, INIT_FAILURE, STARTED, SHUTTING_DOWN, STOPPED, RETRYING_ACCESS_TOKEN_JWT_VERIFICATION,
CRON_TASK_ERROR_LOGGING, WAITING_TO_INIT_STORAGE_MODULE, GET_SESSION_NEW_TOKENS, DEADLOCK_FOUND,
CREATING_NEW_TABLE, SENDING_TELEMETRY, SENT_TELEMETRY, SETTING_ACCESS_TOKEN_SIGNING_KEY_TO_NULL,
CREATING_NEW_TABLE, SENDING_TELEMETRY, SENT_TELEMETRY, UPDATING_ACCESS_TOKEN_SIGNING_KEYS,
PASSWORD_HASH_BCRYPT, PASSWORD_HASH_ARGON, PASSWORD_VERIFY_BCRYPT, PASSWORD_VERIFY_ARGON,
PASSWORD_VERIFY_FIREBASE_SCRYPT, ADDING_REMOTE_ADDRESS_FILTER, LICENSE_KEY_CHECK_NETWORK_CALL,
INVALID_LICENSE_KEY, SERVER_ERROR_DURING_LICENSE_KEY_CHECK_FAIL
Expand Down
Loading