- * This implementation utilises a cryptographically strong {@link SecureRandom} instance to produce the random
- * component of the UUID. The first 6 bytes of the UUID encode the current timestamp in milliseconds, ensuring that
- * generated UUIDs are roughly ordered by creation time.
+ * This implementation utilises a cryptographically strong {@link SecureRandom} instance to produce
+ * the random component of the UUID. The first 6 bytes of the UUID encode the current timestamp in
+ * milliseconds, ensuring that generated UUIDs are roughly ordered by creation time.
*
- * The generated UUID adheres strictly to the layout and variant bits of UUID version 7 as defined in the specification.
- *
+ * The generated UUID adheres strictly to the layout and variant bits of UUID version 7 as defined
+ * in the specification.
+ *
+ * @author zihluwang
+ * @author siujamo
+ * @version 3.0.0
*/
public class SequentialUuidGenerator implements IdentityGenerator {
diff --git a/identity-generator/src/main/java/com/onixbyte/identitygenerator/impl/SnowflakeIdentityGenerator.java b/identity-generator/src/main/java/com/onixbyte/identitygenerator/impl/SnowflakeIdentityGenerator.java
index 9d57099..f3def6d 100644
--- a/identity-generator/src/main/java/com/onixbyte/identitygenerator/impl/SnowflakeIdentityGenerator.java
+++ b/identity-generator/src/main/java/com/onixbyte/identitygenerator/impl/SnowflakeIdentityGenerator.java
@@ -1,18 +1,23 @@
/*
- * Copyright (C) 2024-2025 OnixByte.
+ * Copyright (c) 2024-2025 OnixByte
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
*
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
package com.onixbyte.identitygenerator.impl;
@@ -35,129 +40,17 @@ import java.time.ZoneId;
* 12 bits for sequence number (per millisecond)
*
*
- * When initializing a {@link SnowflakeIdentityGenerator}, you must provide the worker ID and data centre
- * ID, ensuring they are within the valid range defined by the bit size. The generator maintains an
- * internal sequence number that increments for IDs generated within the same millisecond. If the
- * system clock moves backward, an exception is thrown to prevent generating IDs with
- * repeated timestamps.
+ * When initializing a {@link SnowflakeIdentityGenerator}, you must provide the worker ID and data
+ * centre ID, ensuring they are within the valid range defined by the bit size. The generator
+ * maintains an internal sequence number that increments for IDs generated within the
+ * same millisecond. If the system clock moves backward, an exception is thrown to prevent
+ * generating IDs with repeated timestamps.
*
- * @author Zihlu Wang
- * @version 1.1.0
- * @since 1.0.0
+ * @author zihluwang
+ * @version 3.0.0
*/
public final class SnowflakeIdentityGenerator implements IdentityGenerator {
- /**
- * Constructs a SnowflakeGuidGenerator with the default start epoch and custom worker ID, data
- * centre ID.
- *
- * @param dataCentreId the data centre ID (between 0 and 31)
- * @param workerId the worker ID (between 0 and 31)
- */
- public SnowflakeIdentityGenerator(long dataCentreId, long workerId) {
- this(dataCentreId, workerId, DEFAULT_CUSTOM_EPOCH);
- }
-
- /**
- * Constructs a SnowflakeGuidGenerator with a custom epoch, worker ID, and data centre ID.
- *
- * @param dataCentreId the data centre ID (between 0 and 31)
- * @param workerId the worker ID (between 0 and 31)
- * @param startEpoch the custom epoch timestamp (in milliseconds) to start generating IDs from
- * @throws IllegalArgumentException if the start epoch is greater than the current timestamp,
- * or if the worker ID or data centre ID is out of range
- */
- public SnowflakeIdentityGenerator(long dataCentreId, long workerId, long startEpoch) {
- if (startEpoch > currentTimestamp()) {
- throw new IllegalArgumentException("Start Epoch can not be greater than current timestamp!");
- }
-
- var maxWorkerId = ~(-1L << workerIdBits);
- if (workerId > maxWorkerId || workerId < 0) {
- throw new IllegalArgumentException(String.format("Worker Id can't be greater than %d or less than 0",
- maxWorkerId));
- }
-
- var maxDataCentreId = ~(-1L << dataCentreIdBits);
- if (dataCentreId > maxDataCentreId || dataCentreId < 0) {
- throw new IllegalArgumentException(String.format("Data Centre Id can't be greater than %d or less than 0",
- maxDataCentreId));
- }
-
- this.startEpoch = startEpoch;
- this.workerId = workerId;
- this.dataCentreId = dataCentreId;
- }
-
- /**
- * Generates the next unique ID.
- *
- * @return the generated unique ID
- * @throws TimingException if the system clock moves backwards, indicating an invalid sequence
- * of timestamps.
- */
- @Override
- public synchronized Long nextId() {
- var timestamp = currentTimestamp();
-
- // if the current time is less than the timestamp of the last ID generation, it means that
- // the system clock has been set back and an exception should be thrown
- if (timestamp < lastTimestamp) {
- throw new TimingException("Clock moved backwards. Refusing to generate id for %d milliseconds"
- .formatted(lastTimestamp - timestamp));
- }
-
- // if generated at the same time, perform intra-millisecond sequences
- long sequenceBits = 12L;
- if (lastTimestamp == timestamp) {
- long sequenceMask = ~(-1L << sequenceBits);
- sequence = (sequence + 1) & sequenceMask;
- // sequence overflow in milliseconds
- if (sequence == 0) {
- // block to the next millisecond, get a new timestamp
- timestamp = awaitToNextMillis(lastTimestamp);
- }
- }
- // timestamp change, sequence reset in milliseconds
- else {
- sequence = 0L;
- }
-
- // timestamp of last ID generation
- lastTimestamp = timestamp;
-
- // shifted and put together by or operations to form a 64-bit ID
- var timestampLeftShift = sequenceBits + workerIdBits + dataCentreIdBits;
- var dataCentreIdShift = sequenceBits + workerIdBits;
- return ((timestamp - startEpoch) << timestampLeftShift)
- | (dataCentreId << dataCentreIdShift)
- | (workerId << sequenceBits)
- | sequence;
- }
-
- /**
- * Blocks until the next millisecond to obtain a new timestamp.
- *
- * @param lastTimestamp the timestamp when the last ID was generated
- * @return the current timestamp
- */
- private long awaitToNextMillis(long lastTimestamp) {
- var timestamp = currentTimestamp();
- while (timestamp <= lastTimestamp) {
- timestamp = currentTimestamp();
- }
- return timestamp;
- }
-
- /**
- * Returns the current timestamp in milliseconds.
- *
- * @return the current timestamp
- */
- private long currentTimestamp() {
- return LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
- }
-
/**
* Default custom epoch.
*
@@ -200,5 +93,116 @@ public final class SnowflakeIdentityGenerator implements IdentityGenerator
*/
private long lastTimestamp = -1L;
+ /**
+ * Constructs a SnowflakeGuidGenerator with the default start epoch and custom worker ID, data
+ * centre ID.
+ *
+ * @param dataCentreId the data centre ID (between 0 and 31)
+ * @param workerId the worker ID (between 0 and 31)
+ */
+ public SnowflakeIdentityGenerator(long dataCentreId, long workerId) {
+ this(dataCentreId, workerId, DEFAULT_CUSTOM_EPOCH);
+ }
+
+ /**
+ * Constructs a SnowflakeGuidGenerator with a custom epoch, worker ID, and data centre ID.
+ *
+ * @param dataCentreId the data centre ID (between 0 and 31)
+ * @param workerId the worker ID (between 0 and 31)
+ * @param startEpoch the custom epoch timestamp (in milliseconds) to start generating IDs from
+ * @throws IllegalArgumentException if the start epoch is greater than the current timestamp,
+ * or if the worker ID or data centre ID is out of range
+ */
+ public SnowflakeIdentityGenerator(long dataCentreId, long workerId, long startEpoch) {
+ if (startEpoch > currentTimestamp()) {
+ throw new IllegalArgumentException("Start Epoch can not be greater than current timestamp!");
+ }
+
+ var maxWorkerId = ~(-1L << workerIdBits);
+ if (workerId > maxWorkerId || workerId < 0) {
+ throw new IllegalArgumentException(String.format("Worker Id can't be greater than %d or less than 0",
+ maxWorkerId));
+ }
+
+ var maxDataCentreId = ~(-1L << dataCentreIdBits);
+ if (dataCentreId > maxDataCentreId || dataCentreId < 0) {
+ throw new IllegalArgumentException(String.format("Data Centre Id can't be greater than %d or less than 0",
+ maxDataCentreId));
+ }
+
+ this.startEpoch = startEpoch;
+ this.workerId = workerId;
+ this.dataCentreId = dataCentreId;
+ }
+
+ /**
+ * Generates the next unique ID.
+ *
+ * @return the generated unique ID
+ * @throws TimingException if the system clock moves backwards, indicating an invalid sequence
+ * of timestamps.
+ */
+ @Override
+ public synchronized Long nextId() {
+ var timestamp = currentTimestamp();
+
+ // if the current time is less than the timestamp of the last ID generation, it means that
+ // the system clock has been set back and an exception should be thrown
+ if (timestamp < lastTimestamp) {
+ throw new TimingException("Clock moved backwards. Refusing to generate id for %d milliseconds"
+ .formatted(lastTimestamp - timestamp));
+ }
+
+ // if generated at the same time, perform intra-millisecond sequences
+ long sequenceBits = 12L;
+ if (lastTimestamp == timestamp) {
+ long sequenceMask = ~(-1L << sequenceBits);
+ sequence = (sequence + 1) & sequenceMask;
+ // sequence overflow in milliseconds
+ if (sequence == 0) {
+ // block to the next millisecond, get a new timestamp
+ timestamp = awaitToNextMillis(lastTimestamp);
+ }
+ }
+ // timestamp change, sequence reset in milliseconds
+ else {
+ sequence = 0L;
+ }
+
+ // timestamp of last ID generation
+ lastTimestamp = timestamp;
+
+ // shifted and put together by or operations to form a 64-bit ID
+ var timestampLeftShift = sequenceBits + workerIdBits + dataCentreIdBits;
+ var dataCentreIdShift = sequenceBits + workerIdBits;
+ return ((timestamp - startEpoch) << timestampLeftShift)
+ | (dataCentreId << dataCentreIdShift)
+ | (workerId << sequenceBits)
+ | sequence;
+ }
+
+ /**
+ * Blocks until the next millisecond to obtain a new timestamp.
+ *
+ * @param lastTimestamp the timestamp when the last ID was generated
+ * @return the current timestamp
+ */
+ private long awaitToNextMillis(long lastTimestamp) {
+ var timestamp = currentTimestamp();
+ while (timestamp <= lastTimestamp) {
+ timestamp = currentTimestamp();
+ }
+ return timestamp;
+ }
+
+ /**
+ * Returns the current timestamp in milliseconds.
+ *
+ * @return the current timestamp
+ */
+ private long currentTimestamp() {
+ return LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+ }
+
}
diff --git a/identity-generator/src/main/resources/logback.xml b/identity-generator/src/main/resources/logback.xml
index 7beaa9d..288ac4a 100644
--- a/identity-generator/src/main/resources/logback.xml
+++ b/identity-generator/src/main/resources/logback.xml
@@ -1,25 +1,33 @@
-
-
-
-
+
+
+
+
+
${COLOURFUL_OUTPUT}
@@ -28,4 +36,4 @@
-
\ No newline at end of file
+
diff --git a/jwt-toolbox-auth0/README.md b/jwt-toolbox-auth0/README.md
index ee055b3..d3fca65 100644
--- a/jwt-toolbox-auth0/README.md
+++ b/jwt-toolbox-auth0/README.md
@@ -1,59 +1,56 @@
-# Module `simple-jwt-authzero`
+# JWT Toolbox :: Auth0
## Introduction
-The `simple-jwt-authzero` module is an implementation of module `simple-jwt-facade` which uses the third-party library `com.auth0:java-jwt`. By using this module can help you use JWT to help you in your application.
-
-## Prerequisites
-
-This whole `JDevKit` is developed by **JDK 17**, which means you have to use JDK 17 for better experience.
-
-## Installation
-
-> This module has already imported `simple-jwt-facade`, there is no need to import it again.
+**JWT Toolbox :: Auth0** module is an implementation of module JWT Toolbox, which uses third-party
+library `com.auth0:java-jwt`. By using this module can help you use JWT to help you in
+your application.
### If you are using `Maven`
-It is quite simple to install this module by `Maven`. The only thing you need to do is find your `pom.xml` file in the project, then find the `` node in the `` node, and add the following codes to `` node:
+It is quite simple to install this module by `Maven`. The only thing you need to do is find your
+`pom.xml` file in the project, then find the `` node in the `` node, and add
+the following codes to `` node:
```xml
+
- cn.org.codecrafters
- simple-jwt-authzero
- ${simple-jwt-authzero.version}
+ com.onixbyte
+ jwt-toolbox-auth0
+ ${jwt-toolbox-auth0.version}
```
-And run `mvn dependency:get` in your project root folder(i.e., if your `pom.xml` is located at `/path/to/your/project/pom.xml`, then your current work folder should be `/path/to/your/project`), then `Maven` will automatically download the `jar` archive from `Maven Central Repository`. This could be **MUCH EASIER** if you are using IDE(i.e., IntelliJ IDEA), the only thing you need to do is click the refresh button of `Maven`.
+And run `mvn dependency:get` in your project root folder(i.e., if your `pom.xml` is located at
+`/path/to/your/project/pom.xml`, then your current work folder should be `/path/to/your/project`),
+then `Maven` will automatically download the `jar` archive from `Maven Central Repository`.
+This could be **MUCH EASIER** if you are using IDE(i.e., IntelliJ IDEA), the only thing you need to
+do is click the refresh button of `Maven`.
-If you are restricted using the Internet, and have to make `Maven` offline, you could follow the following steps.
+If you are restricted using the Internet, and have to make `Maven` offline, you could follow the
+following steps.
-1. Download the `jar` file from any place you can get and transfer the `jar` files to your work computer.
-2. Move the `jar` files to your local `Maven` Repository as the path of `/path/to/maven_local_repo/cn/org/codecrafters/simple-jwt-facade/`.
+1. Download the `jar` file from any place you can get and transfer the `jar` files to your
+ work computer.
+2. Move the `jar` files to your local `Maven` Repository as the path of
+ `/path/to/maven_local_repo/com/onixbyte/jwt-toolbox-auth0/`.
### If you are using `Gradle`
Add this module to your project with `Gradle` is much easier than doing so with `Maven`.
-Find `build.gradle` in the needed project, and add the following code to the `dependencies` closure in the build script:
+Find `build.gradle` in the needed project, and add the following code to the `dependencies` closure
+in the build script:
```groovy
-implementation 'cn.org.codecrafters:simple-jwt-authzero:${simple-jwt-authzero.version}'
+implementation 'com.onixbyte:jwt-toolbox-auth0:${jwt-toolbox-auth0.version}'
```
-### If you are not using `Maven` or `Gradle`
-
-1. Download the `jar` file from the Internet.
-2. Create a folder in your project and name it as a name you like(i.e., for me, I prefer `vendor`).
-3. Put the `jar` file to the folder you just created in Step 2.
-4. Add this folder to your project `classpath`.
-
-## Use the `AuthzeroTokenResolver`
-
-We have implemented `TokenResolver` to make sure you can add JWT to your Java application as soon as possible. All you need to do is to create an instance of `com.onixbyte.jwt.auth0.AuthzeroTokenResolver` and other operations to JWT could follow our instruction in [`simple-jwt-facade`](../simple-jwt-facade/README.md).
-
## Contact
-If you have any suggestions, ideas, don't hesitate contacting us via [GitHub Issues](https://github.com/CodeCraftersCN/jdevkit/issues/new) or [Discord Community](https://discord.gg/NQK9tjcBB8).
+If you have any suggestions, ideas, don't hesitate contacting us via
+[GitHub Issues](https://github.com/onixbyte/onixbyte-toolbox/issues/new).
-If you face any bugs while using our library and you are able to fix any bugs in our library, we would be happy to accept pull requests from you on [GitHub](https://github.com/CodeCraftersCN/jdevkit/compare).
+If you face any bugs while using our library and you are able to fix any bugs in our library, we
+would be happy to accept pull requests from you on
+[GitHub](https://github.com/onixbyte/onixbyte-toolbox/compare).
diff --git a/jwt-toolbox-auth0/build.gradle.kts b/jwt-toolbox-auth0/build.gradle.kts
index 91c2151..110eeb9 100644
--- a/jwt-toolbox-auth0/build.gradle.kts
+++ b/jwt-toolbox-auth0/build.gradle.kts
@@ -1,18 +1,23 @@
/*
- * Copyright (C) 2024-2025 OnixByte.
+ * Copyright (c) 2024-2025 OnixByte
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
*
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
*/
import java.net.URI
@@ -90,8 +95,8 @@ publishing {
}
scm {
- connection = "scm:git:git://github.com:OnixByte/JDevKit.git"
- developerConnection = "scm:git:git://github.com:OnixByte/JDevKit.git"
+ connection = "scm:git:git://github.com:onixbyte/onixbyte-toolbox.git"
+ developerConnection = "scm:git:git://github.com:onixbyte/onixbyte-toolbox.git"
url = projectGithubUrl
}
diff --git a/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenGenerator.java b/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenGenerator.java
new file mode 100644
index 0000000..e5c82eb
--- /dev/null
+++ b/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenGenerator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2024-2025 OnixByte
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.onixbyte.jwt.auth0;
+
+import com.onixbyte.jwt.TokenGenerator;
+
+public class Auth0TokenGenerator implements TokenGenerator {
+}
diff --git a/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenParser.java b/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenParser.java
new file mode 100644
index 0000000..7e30b50
--- /dev/null
+++ b/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/Auth0TokenParser.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2024-2025 OnixByte
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.onixbyte.jwt.auth0;
+
+import com.onixbyte.identitygenerator.IdentityGenerator;
+import com.auth0.jwt.JWTCreator;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import com.onixbyte.jwt.TokenParser;
+
+/**
+ *
+ *
+ * @author zihluwang
+ * @version 3.0.0
+ * @see IdentityGenerator
+ * @see Algorithm
+ * @see JWTVerifier
+ * @see JWTCreator
+ * @see JWTCreator.Builder
+ * @since 1.0.0
+ */
+public class Auth0TokenParser implements TokenParser {
+
+
+}
diff --git a/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/AuthzeroTokenResolver.java b/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/AuthzeroTokenResolver.java
deleted file mode 100644
index b6e6206..0000000
--- a/jwt-toolbox-auth0/src/main/java/com/onixbyte/jwt/auth0/AuthzeroTokenResolver.java
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2024-2025 OnixByte.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * 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 com.onixbyte.jwt.auth0;
-
-import com.onixbyte.common.util.Base64Util;
-import com.onixbyte.crypto.algorithm.ecdsa.ECPrivateKeyLoader;
-import com.onixbyte.identitygenerator.IdentityGenerator;
-import com.onixbyte.jwt.TokenPayload;
-import com.onixbyte.jwt.TokenResolver;
-import com.onixbyte.jwt.annotations.ExcludeFromPayload;
-import com.onixbyte.jwt.annotations.TokenEnum;
-import com.onixbyte.jwt.constants.PredefinedKeys;
-import com.onixbyte.jwt.constants.TokenAlgorithm;
-import com.auth0.jwt.JWT;
-import com.auth0.jwt.JWTCreator;
-import com.auth0.jwt.algorithms.Algorithm;
-import com.auth0.jwt.interfaces.DecodedJWT;
-import com.auth0.jwt.interfaces.JWTVerifier;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.onixbyte.jwt.exceptions.IllegalKeyPairException;
-import com.onixbyte.jwt.exceptions.IllegalSecretException;
-import com.onixbyte.jwt.exceptions.UnsupportedAlgorithmException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.InvocationTargetException;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.time.Duration;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.*;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-/**
- * The {@code AuthzeroTokenResolver} class is an implementation of the {@link TokenResolver}
- * interface. It uses the {@code com.auth0:java-jwt} library to handle JSON Web Token (JWT)
- * resolution. This resolver provides functionality to create, extract, verify, and renew JWT
- * tokens using various algorithms and custom payload data.
- *
- * Usage:
- * To use the {@code AuthzeroTokenResolver}, first, create an instance of this class:
- *
{@code
- * TokenResolver tokenResolver =
- * new AuthzeroTokenResolver(TokenAlgorithm.HS256,
- * "Token Subject",
- * "Token Issuer",
- * "Token Secret");
- * }
- *
- * Then, you can utilize the various methods provided by this resolver to handle JWT tokens:
- *
{@code
- * // Creating a new JWT token
- * String token =
- * tokenResolver.createToken(Duration.ofHours(1),
- * "your_subject",
- * "your_audience",
- * customPayloads);
- *
- * // Extracting payload data from a JWT token
- * DecodedJWT decodedJWT = tokenResolver.resolve(token);
- * T payloadData = decodedJWT.extract(token, T.class);
- *
- * // Renewing an existing JWT token
- * String renewedToken =
- * tokenResolver.renew(token, Duration.ofMinutes(30), customPayloads);
- * }
- *
- * Note:
- * It is essential to configure the appropriate algorithms, secret, and issuer according to your
- * specific use case when using this resolver. Additionally, ensure that the
- * {@code com.auth0:java-jwt} library is correctly configured in your project's dependencies.
- *
- * @author Zihlu Wang
- * @version 1.1.1
- * @see IdentityGenerator
- * @see Algorithm
- * @see JWTVerifier
- * @see JWTCreator
- * @see JWTCreator.Builder
- * @since 1.0.0
- */
-public class AuthzeroTokenResolver implements TokenResolver {
-
- private final static Logger log = LoggerFactory.getLogger(AuthzeroTokenResolver.class);
-
- /**
- * Create a builder of {@link AuthzeroTokenResolver}.
- *
- * @return a builder instance
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Builder for {@link AuthzeroTokenResolver}
- */
- public static class Builder {
-
- /**
- * IdentityGenerator used for generating unique identifiers for "jti" claim in JWT tokens.
- */
- private IdentityGenerator> jtiCreator;
-
- /**
- * The algorithm used for signing and verifying JWT tokens.
- */
- private Algorithm algorithm;
-
- /**
- * The issuer claim value to be included in JWT tokens.
- */
- private String issuer;
-
- /**
- * Jackson JSON handler.
- */
- private ObjectMapper objectMapper;
-
- /**
- * The secret to sign a JWT with HMAC based algorithm.
- */
- private String secret;
-
- /**
- * The private key to sign a JWT with ECDSA based algorithm.
- */
- private ECPrivateKey privateKey;
-
- /**
- * The public key to read a JWT with ECDSA based algorithm.
- */
- private ECPublicKey publicKey;
-
- /**
- * Private constructor to prevent instantiation of this utility class.
- */
- private Builder() {
- }
-
- /**
- * Set the secret to sign a JWT.
- *
- * @param secret the secret
- * @return the builder instance
- */
- public Builder secret(String secret) {
- this.secret = secret;
- return this;
- }
-
- /**
- * Set the key pair to sign a JWT.
- *
- * @param publicKey the pem formatted public key text
- * @param privateKey the pem formatted private key text
- * @return the builder instance
- */
- public Builder keyPair(String publicKey, String privateKey) {
- var keyLoader = new ECPrivateKeyLoader();
- // this.publicKey = keyLoader.loadPublicKey(publicKey);
- this.privateKey = keyLoader.loadPrivateKey(privateKey);
- return this;
- }
-
- /**
- * Set the algorithm to sign a JWT.
- *
- * A secret required by HMAC-based algorithms, or key pair required by ECDSA-based
- * algorithms need to be set before initialise an algorithm.
- *
- * @param algorithm an {@link TokenAlgorithm} value
- * @return the builder instance
- */
- public Builder algorithm(TokenAlgorithm algorithm) {
- // check the secret or key pair before algorithm initialised
- if (HMAC_ALGORITHMS.containsKey(algorithm)) {
- if (Objects.isNull(secret) || secret.isBlank()) {
- throw new IllegalSecretException("""
- Please specify a secret before define an algorithm.""");
- }
- } else if (ECDSA_ALGORITHMS.containsKey(algorithm)) {
- if (Objects.isNull(publicKey) || Objects.isNull(privateKey)) {
- throw new IllegalKeyPairException("""
- Please specify a ECDSA key pair before define an algorithm.""");
- }
- }
-
- // initialise algorithm
- this.algorithm = switch (algorithm) {
- case HS256, HS384, HS512 -> HMAC_ALGORITHMS.get(algorithm).apply(secret);
- case ES256, ES384, ES512 -> ECDSA_ALGORITHMS.get(algorithm)
- .apply(publicKey, privateKey);
- default -> throw new UnsupportedAlgorithmException("""
- This algorithm is not supported yet.""");
- };
- return this;
- }
-
- /**
- * Set the object mapper.
- *
- * @param objectMapper an object mapper
- * @return the builder instance
- */
- public Builder objectMapper(ObjectMapper objectMapper) {
- this.objectMapper = objectMapper;
- return this;
- }
-
- /**
- * Set the creator of JWT id.
- *
- * @param jtiCreator a creator to create JWT id
- * @return the builder instance
- */
- public Builder jtiCreator(IdentityGenerator> jtiCreator) {
- this.jtiCreator = jtiCreator;
- return this;
- }
-
- /**
- * Set the issuer of created JWT.
- *
- * @param issuer the person or organisation issued this JWT
- * @return the builder instance
- */
- public Builder issuer(String issuer) {
- this.issuer = issuer;
- return this;
- }
-
- /**
- * Create an {@link AuthzeroTokenResolver} instance
- *
- * @return created instance
- */
- public AuthzeroTokenResolver build() {
- return new AuthzeroTokenResolver(jtiCreator, algorithm, issuer, objectMapper);
- }
- }
-
- /**
- * Creates a new token with the specified expiration duration, subject, and
- * audience.
- *
- * @param expireAfter the duration after which the token will expire
- * @param subject the subject of the token
- * @param audience the audience for which the token is intended
- * @return the generated token as a {@code String}
- */
- @Override
- public String createToken(Duration expireAfter, String audience, String subject) {
- final var builder = JWT.create();
- buildBasicInfo(builder, expireAfter, subject, audience);
- return buildToken(builder);
- }
-
- /**
- * Creates a new token with the specified expiration time, subject,
- * audience, and custom payload data.
- *
- * @param expireAfter the duration after which the token will expire
- * @param subject the subject of the token
- * @param audience the audience for which the token is intended
- * @param payloads the custom payload data to be included in the token
- * @return the generated token as a {@code String}
- */
- @Override
- public String createToken(Duration expireAfter, String audience, String subject, Map payloads) {
- // Create token.
- final var builder = JWT.create();
- buildBasicInfo(builder, expireAfter, subject, audience);
- buildMapClaims(builder, payloads);
- return buildToken(builder);
- }
-
- /**
- * Creates a new token with the specified expiration time, subject,
- * audience, and strongly-typed payload data.
- *
- * @param expireAfter the duration after which the token will expire
- * @param subject the subject of the token
- * @param audience the audience for which the token is intended
- * @param payload the strongly-typed payload data to be included in the
- * token
- * @return the generated token as a {@code String}
- */
- @Override
- public String createToken(Duration expireAfter, String audience, String subject, T payload) {
- final var builder = JWT.create();
- buildBasicInfo(builder, expireAfter, subject, audience);
-
- var payloadClass = payload.getClass();
- var fields = payloadClass.getDeclaredFields();
-
- for (var field : fields) {
- try {
- var fieldName = field.getName();
- // Skip the fields which are annotated with ExcludeFromPayload
- if (field.isAnnotationPresent(ExcludeFromPayload.class))
- continue;
-
- Object invokeObj = payload;
- var getter = payloadClass.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
- if (field.isAnnotationPresent(TokenEnum.class)) {
- var tokenEnum = field.getAnnotation(TokenEnum.class);
- invokeObj = getter.invoke(payload);
- getter = field.getType().getDeclaredMethod("get" + tokenEnum.propertyName().substring(0, 1).toUpperCase() + tokenEnum.propertyName().substring(1));
- }
-
- // Build Claims
- addClaim(builder, fieldName, getter.invoke(invokeObj));
- } catch (IllegalAccessException e) {
- log.error("Cannot access field {}!", field.getName());
- } catch (NoSuchMethodException e) {
- log.error("Unable to find setter according to given field name.", e);
- } catch (InvocationTargetException e) {
- log.info("Cannot invoke method.", e);
- }
- }
-
- return buildToken(builder);
- }
-
- /**
- * Resolves the given token into a {@link DecodedJWT} object.
- *
- * @param token the token to be resolved
- * @return a {@link DecodedJWT} object
- */
- @Override
- public DecodedJWT resolve(String token) {
- return jwtVerifier.verify(token);
- }
-
- /**
- * Extracts the payload information from the given token and maps it to the
- * specified target type.
- *
- * @param token the token from which to extract the payload
- * @param targetType the target class representing the payload data type
- * @return an instance of the specified target type with the extracted
- * payload data, or {@code null} when extraction fails
- */
- @Override
- public T extract(String token, Class targetType) {
- try {
- // Get claims from token.
- var payloads = objectMapper.readValue(Base64Util.decodeUrlComponents(resolve(token).getPayload()), new MapTypeReference());
- // Get the no-argument constructor to create an instance.
- var bean = targetType.getConstructor().newInstance();
-
- for (var entry : payloads.entrySet()) {
- // Jump all JWT pre-defined properties and the fields that are annotated to be excluded.
- if (PredefinedKeys.KEYS.contains(entry.getKey()) || targetType.getDeclaredField(entry.getKey()).isAnnotationPresent(ExcludeFromPayload.class))
- continue;
-
- var field = targetType.getDeclaredField(entry.getKey());
- var setter = targetType.getDeclaredMethod("set" + entry.getKey().substring(0, 1).toUpperCase() + entry.getKey().substring(1), field.getType());
- var fieldValue = entry.getValue();
- if (field.isAnnotationPresent(TokenEnum.class)) {
- var annotation = field.getAnnotation(TokenEnum.class);
- var enumStaticLoader = field.getType().getDeclaredMethod("loadBy" + annotation.propertyName().substring(0, 1).toUpperCase() + annotation.propertyName().substring(1), annotation.dataType().getMappedClass());
- fieldValue = enumStaticLoader.invoke(null, fieldValue);
- }
-
- if (setter.canAccess(bean)) {
- setter.invoke(bean, fieldValue);
- } else {
- log.error("Setter for field {} can't be accessed.", entry.getKey());
- }
- }
- return bean;
- } catch (JsonProcessingException e) {
- log.error("Unable to read payload as a Map.", e);
- } catch (InvocationTargetException | InstantiationException | IllegalAccessException |
- NoSuchMethodException e) {
- log.error("Unable to load the constructor or setter.", e);
- } catch (NoSuchFieldException e) {
- log.error("Unable to load the field.", e);
- }
- return null;
- }
-
- /**
- * Re-generate a new token with the payload in the old one.
- *
- * @param oldToken the old token
- * @param expireAfter how long the new token can be valid for
- * @return re-generated token with the payload in the old one or
- * {@code null} if an {@link JsonProcessingException} occurred.
- */
- @Override
- public String renew(String oldToken, Duration expireAfter) {
- var resolved = resolve(oldToken);
-
- try {
- var payload = objectMapper.readValue(Base64Util.decodeUrlComponents(resolved.getPayload()), ObjectNode.class);
- payload.remove(PredefinedKeys.KEYS);
-
- var payloadMap = objectMapper.convertValue(payload, new MapTypeReference());
- return createToken(expireAfter, resolved.getAudience().get(0), resolved.getSubject(), payloadMap);
- } catch (JsonProcessingException e) {
- log.error("Cannot read payload content, error details:", e);
- }
-
- return null;
- }
-
- /**
- * Renews the given expired token with the specified custom payload data.
- *
- * @param oldToken the expired token to be renewed
- * @param payload the custom payload data to be included in the renewed
- * token
- * @return the renewed token as a {@code String}
- */
- @Override
- public String renew(String oldToken, Duration expireAfter, Map payload) {
- final var resolvedToken = this.resolve(oldToken);
- var audience = resolvedToken.getAudience().get(0);
-
- return createToken(expireAfter, audience, resolvedToken.getSubject(), payload);
- }
-
- /**
- * Renews the given expired token with the specified custom payload data.
- *
- * @param oldToken the expiring token to be renewed
- * @param payload the custom payload data to be included in the renewed
- * token
- * @return the renewed token as a {@code String}
- */
- @Override
- public String renew(String oldToken, Map payload) {
- return renew(oldToken, Duration.ofMinutes(30), payload);
- }
-
- /**
- * Renews the given expired token with the new specified strongly-typed
- * payload data.
- *
- * @param oldToken the expiring token to be renewed
- * @param payload the strongly-typed payload data to be included in the
- * renewed token
- * @return the renewed token as a {@code String}
- */
- @Override
- public String renew(String oldToken, Duration expireAfter, T payload) {
- final var resolvedToken = this.resolve(oldToken);
- var audience = resolvedToken.getAudience().get(0);
-
- return createToken(expireAfter, audience, resolvedToken.getSubject(), payload);
- }
-
- /**
- * Renews the given expired token with the new specified strongly-typed
- * payload data.
- *
- * @param the type of the payload data, must implement
- * {@link TokenPayload}
- * @param oldToken the expired token to be renewed
- * @param payload the strongly-typed payload data to be included in the
- * renewed token
- * @return the renewed token as a {@link String}
- */
- @Override
- public String renew(String oldToken, T payload) {
- return renew(oldToken, Duration.ofMinutes(30), payload);
- }
-
- /**
- * Builds the basic information of the JSON Web Token (JWT) using the
- * provided parameters and adds it to the JWTCreator.Builder.
- *
- * @param subject the subject claim value to be included in the JWT
- * @param audience an array of audience claim values to be included in
- * the JWT
- * @param expireAfter the duration after which the JWT will expire
- * @param builder the JWTCreator.Builder instance to which the basic
- * information will be added
- */
- private void buildBasicInfo(JWTCreator.Builder builder, Duration expireAfter, String subject, String... audience) {
- var now = LocalDateTime.now();
-
- // bind issuer (iss)
- builder.withIssuer(issuer);
- // bind issued at (iat)
- builder.withIssuedAt(now.atZone(ZoneId.systemDefault()).toInstant());
- // bind not before (nbf)
- builder.withNotBefore(now.atZone(ZoneId.systemDefault()).toInstant());
- // bind audience (aud)
- builder.withAudience(audience);
- // bind subject (sub)
- builder.withSubject(subject);
- // bind expire at (exp)
- builder.withExpiresAt(now.plus(expireAfter).atZone(ZoneId.systemDefault()).toInstant());
- // bind JWT Id (jti)
- builder.withJWTId(jtiCreator.nextId().toString());
- }
-
- /**
- * Add a claim to a builder.
- *
- * @param builder the builder to build this JSON Web Token
- * @param name the property name
- * @param value the property value
- */
- private void addClaim(JWTCreator.Builder builder, String name, Object value) {
- if (Objects.nonNull(value)) {
- if (value instanceof Boolean v) {
- builder.withClaim(name, v);
- } else if (value instanceof Double v) {
- builder.withClaim(name, v);
- } else if (value instanceof Float v) {
- builder.withClaim(name, v.doubleValue());
- } else if (value instanceof Integer v) {
- builder.withClaim(name, v);
- } else if (value instanceof Long v) {
- builder.withClaim(name, v);
- } else if (value instanceof String v) {
- builder.withClaim(name, v);
- } else if (value instanceof Date v) {
- builder.withClaim(name, v);
- } else if (value instanceof List> v) {
- builder.withClaim(name, v);
- } else {
- log.warn("""
- Unable to determine the type of field {}, we will handle it as a String.""", name);
- builder.withClaim(name, value.toString());
- }
- } else {
- builder.withNullClaim(name);
- }
- }
-
- /**
- * Builds the custom claims of the JSON Web Token (JWT) using the provided
- * Map of claims and adds them to the JWTCreator.Builder.
- *
- * This method is used to add custom claims to the JWT. It takes a Map of
- * claims, where each entry represents a custom claim name (key) and its
- * corresponding value (value). The custom claims will be added to the JWT
- * using the JWTCreator.Builder.
- *
- * @param claims a Map containing the custom claims to be added to the JWT
- * @param builder the JWTCreator.Builder instance to which the custom
- * claims will be added
- */
- private void buildMapClaims(JWTCreator.Builder builder, Map claims) {
- if (Objects.nonNull(claims)) {
- for (var e : claims.entrySet()) {
- addClaim(builder, e.getKey(), e.getValue());
- }
- }
- }
-
- /**
- * Finish creating a token.
- *
- * This is the final step of create a token, to sign this token.
- *
- * @param builder the builder to build this JWT
- * @return the generated token as a {@code String}
- */
- private String buildToken(JWTCreator.Builder builder) {
- return builder.sign(algorithm);
- }
-
- /**
- * Default type reference for Map.
- */
- public static class MapTypeReference extends TypeReference