diff --git a/simple-jwt/build.gradle.kts b/simple-jwt/build.gradle.kts deleted file mode 100644 index 03ee131..0000000 --- a/simple-jwt/build.gradle.kts +++ /dev/null @@ -1,51 +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. - */ - -plugins { - id("java") - id("java-library") - id("maven-publish") - id("signing") -} - -val artefactVersion: String by project -val projectUrl: String by project -val projectGithubUrl: String by project -val licenseName: String by project -val licenseUrl: String by project - -group = "com.onixbyte" -version = artefactVersion - -repositories { - mavenCentral() -} - -dependencies { - compileOnly(libs.slf4j) - implementation(libs.logback) - api(project(":devkit-core")) - api(project(":devkit-utils")) - implementation(libs.jackson.core) - implementation(libs.jackson.databind) - testImplementation(platform(libs.junit.bom)) - testImplementation(libs.junit.jupiter) -} - -tasks.test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenCreator.java b/simple-jwt/src/main/java/com/onixbyte/jwt/TokenCreator.java deleted file mode 100644 index 1e3300c..0000000 --- a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenCreator.java +++ /dev/null @@ -1,46 +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; - -/** - * Interface for creating and signing JSON Web Tokens (JWTs). - *
- * Defines a contract for implementations that generate signed JWTs from a given payload. The - * resulting token is typically a string in the format "header.payload.signature", where the - * signature is created using a cryptographic algorithm specific to the implementation. - * - * @author zihluwang - */ -public interface TokenCreator { - - /** - * Signs a token payload to create a JWT. - *
- * Takes a {@link TokenPayload} object, serialises its claims, and generates a signed - * JWT string. The specific signing algorithm (e.g., HMAC, RSA, ECDSA) depends on - * the implementation. - * - * @param payload the {@link TokenPayload} containing claims to include in the token - * @return the signed JWT as a string in the format "header.payload.signature" - * @throws IllegalArgumentException if the payload cannot be serialised to JSON due to invalid - * data or structure, or if the signing process fails due to - * configuration issues - */ - String sign(TokenPayload payload); - -} diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenManager.java b/simple-jwt/src/main/java/com/onixbyte/jwt/TokenManager.java deleted file mode 100644 index f8e8b52..0000000 --- a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenManager.java +++ /dev/null @@ -1,47 +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; - -/** - * Interface for managing JSON Web Tokens (JWTs) with support for signing, verification, and - * payload extraction. - *
- * Combines the functionality of {@link TokenCreator} for creating signed JWTs and
- * {@link TokenResolver} for verifying and parsing them, while adding the ability to extract the
- * payload as a custom type {@code T}. Implementations are expected to handle both token generation
- * and resolution, providing a unified interface for JWT operations.
- *
- * @param
- * Retrieves the payload from the token and transforms it into the specified type using an
- * implementation-specific mechanism, such as an adapter or mapper.
- *
- * @param token the JWT string from which to extract the payload
- * @return the payload converted to an object of type {@code T}
- * @throws IllegalArgumentException if the token is malformed, the signature is invalid, or the
- * payload cannot be deserialised or converted to
- * type {@code T}
- */
- T extract(String token);
-}
\ No newline at end of file
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenPayload.java b/simple-jwt/src/main/java/com/onixbyte/jwt/TokenPayload.java
deleted file mode 100644
index 3a0d25d..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/TokenPayload.java
+++ /dev/null
@@ -1,380 +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;
-
-import com.onixbyte.jwt.constant.RegisteredClaims;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.*;
-
-/**
- * A builder-style class for constructing JSON Web Token (JWT) payloads.
- *
- * Provides a fluent interface to set standard registered claims (e.g., subject, issuer, audience)
- * and custom claims for a JWT payload. The class supports chaining method calls to build the
- * payload incrementally, which can then be retrieved as a map for use in JWT creation. Ensures that
- * registered claims are set using dedicated methods to prevent misuse.
- *
- * @author zihluwang
- */
-public class TokenPayload {
-
- /**
- * Creates a new instance of {@link TokenPayload} with an empty payload.
- *
- * Initialises the payload with empty collections for claims and audiences, ready for
- * configuration via the builder methods.
- *
- * @return a new {@link TokenPayload} instance
- */
- public static TokenPayload createPayload() {
- return new TokenPayload();
- }
-
- /**
- * The map storing custom claims for the JWT payload.
- */
- private final Map
- * Initialises the internal collections for storing claims and audiences, preventing direct
- * instantiation outside the class.
- */
- private TokenPayload() {
- payload = new HashMap<>();
- audiences = new ArrayList<>();
- }
-
- /**
- * Adds a single audience to the JWT payload.
- *
- * Appends the specified audience identifier to the list of audiences, allowing the token to be
- * validated for multiple recipients.
- *
- * @param audience the audience identifier to add
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withAudience(String audience) {
- audiences.add(audience);
- return this;
- }
-
- /**
- * Adds multiple audiences to the JWT payload.
- *
- * Appends all provided audience identifiers to the list of audiences, enabling the token to be
- * validated for multiple recipients.
- *
- * @param audiences the audience identifiers to add
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withAudiences(String... audiences) {
- this.audiences.addAll(Arrays.asList(audiences));
- return this;
- }
-
- /**
- * Sets the subject of the JWT payload.
- *
- * Specifies the principal that is the subject of the token, typically identifying the user or
- * entity the token represents.
- *
- * @param subject the subject identifier
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withSubject(String subject) {
- this.subject = subject;
- return this;
- }
-
- /**
- * Sets the issuer of the JWT payload.
- *
- * Specifies the entity that issued the token, allowing recipients to verify the token's origin.
- *
- * @param issuer the issuer identifier
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withIssuer(String issuer) {
- this.issuer = issuer;
- return this;
- }
-
- /**
- * Sets the unique identifier for the JWT payload.
- *
- * Assigns a unique token ID to the JWT, which can be used to prevent token reuse or for
- * tracking purposes.
- *
- * @param tokenId the unique token identifier
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withTokenId(String tokenId) {
- this.tokenId = tokenId;
- return this;
- }
-
- /**
- * Sets the expiration time for the JWT payload.
- *
- * Specifies when the token expires, converted to seconds since the Unix epoch based on the
- * system's default time zone.
- *
- * @param expiresAt the expiration time as a {@link LocalDateTime}
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withExpiresAt(LocalDateTime expiresAt) {
- this.expiresAt = expiresAt.atZone(ZoneId.systemDefault())
- .toInstant()
- .getEpochSecond();
- return this;
- }
-
- /**
- * Sets the time before which the JWT must not be accepted.
- *
- * Specifies the "not before" time, converted to seconds since the Unix epoch based on the
- * system's default time zone.
- *
- * @param notBefore the time before which the token is invalid, as a {@link LocalDateTime}
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withNotBefore(LocalDateTime notBefore) {
- this.notBefore = notBefore.atZone(ZoneId.systemDefault())
- .toInstant()
- .getEpochSecond();
- return this;
- }
-
- /**
- * Sets the issuance time for the JWT payload.
- *
- * Specifies when the token was issued, converted to seconds since the Unix epoch based on the
- * system's default time zone.
- *
- * @param issuedAt the issuance time as a {@link LocalDateTime}
- * @return this {@link TokenPayload} instance for method chaining
- */
- public TokenPayload withIssuedAt(LocalDateTime issuedAt) {
- this.issuedAt = issuedAt.atZone(ZoneId.systemDefault())
- .toInstant()
- .getEpochSecond();
- return this;
- }
-
- /**
- * Adds a custom claim to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @param value the value of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withClaim(String name, String value) {
- checkClaimName(name);
-
- this.payload.put(name, value);
- return this;
- }
-
- /**
- * Adds a custom claim to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @param value the value of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withClaim(String name, Long value) {
- checkClaimName(name);
-
- this.payload.put(name, value);
- return this;
- }
-
- /**
- * Adds a custom claim to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @param value the value of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withClaim(String name, Double value) {
- checkClaimName(name);
-
- this.payload.put(name, value);
- return this;
- }
-
- /**
- * Adds a custom claim to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @param value the value of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withClaim(String name, Boolean value) {
- checkClaimName(name);
-
- this.payload.put(name, value);
- return this;
- }
-
- /**
- * Adds a custom claim to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @param value the value of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withClaim(String name, LocalDateTime value) {
- checkClaimName(name);
-
- this.payload.put(name, value);
- return this;
- }
-
- /**
- * Adds a custom claim with null value to the JWT payload.
- *
- * Stores a custom key-value pair in the payload, provided the key is not a registered claim.
- * Registered claims must be set using their dedicated methods to ensure proper handling.
- *
- * @param name the name of the custom claim
- * @return this {@link TokenPayload} instance for method chaining
- * @throws IllegalStateException if the claim name is a registered claim
- */
- public TokenPayload withNullClaim(String name) {
- checkClaimName(name);
-
- this.payload.put(name, null);
- return this;
- }
-
- /**
- * Checks if the JWT payload has a valid issuer.
- *
- * Returns {@code true} if the issuer is non-null and not blank, indicating that an issuer has
- * been set.
- *
- * @return {@code true} if an issuer is set, {@code false} otherwise
- */
- public boolean hasIssuer() {
- return Objects.nonNull(issuer) && !issuer.isBlank();
- }
-
- /**
- * Retrieves the complete JWT payload as a map.
- *
- * Constructs a map containing all custom claims, registered claims (if set), and audiences.
- * Only non-empty or non-blank values are included to ensure a clean payload.
- *
- * @return a map containing the JWT payload
- */
- public Map
- * Defines a contract for implementations that parse, verify, and extract components from JWTs.
- * Provides methods to validate the token's signature, retrieve its header and payload, and split it
- * into raw components. Implementations are expected to handle cryptographic verification and JSON
- * deserialisation specific to their signing algorithm.
- *
- * @author zihluwang
- */
-public interface TokenResolver {
-
- /**
- * Verifies the signature of the provided JWT.
- *
- * Splits the token into its components and checks the signature's validity using the
- * implementation's configured algorithm and key. If the signature does not match, an exception
- * is thrown.
- *
- * @param token the JWT string to verify
- * @throws IllegalArgumentException if the token is malformed or the signature verification
- * fails due to an invalid algorithm, key, or
- * mismatched signature
- */
- void verify(String token);
-
- /**
- * Retrieves the header claims from the provided JWT.
- *
- * Decodes the Base64-encoded header and deserialises it into a map of strings.
- *
- * @param token the JWT string from which to extract the header
- * @return a map containing the header claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the header cannot be
- * deserialised due to invalid JSON format
- */
- Map
- * Decodes the Base64-encoded payload, deserialises it into a map, and removes any registered
- * claims as defined in {@link RegisteredClaims}.
- *
- * @param token the JWT string from which to extract the payload
- * @return a map containing the custom payload claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the payload cannot be
- * deserialised due to invalid JSON format
- */
- Map
- * Provides a default implementation that separates the token string into its three parts using
- * dot separators and returns them as a {@link RawTokenComponent}.
- *
- * @param token the JWT string to split
- * @return a {@link RawTokenComponent} containing the header, payload, and signature as strings
- * @throws IllegalArgumentException if the token does not consist of exactly three parts
- * separated by dots
- */
- default RawTokenComponent splitToken(String token) {
- var tokenTuple = token.split("\\.");
-
- if (tokenTuple.length != 3) {
- throw new IllegalArgumentException(
- "The provided JWT is invalid: it must consist of exactly three parts separated by dots.");
- }
-
- return new RawTokenComponent(tokenTuple[0], tokenTuple[1], tokenTuple[2]);
- }
-
-}
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/Algorithm.java b/simple-jwt/src/main/java/com/onixbyte/jwt/constant/Algorithm.java
deleted file mode 100644
index 6a37d57..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/Algorithm.java
+++ /dev/null
@@ -1,137 +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.constant;
-
-/**
- * Enumeration of cryptographic algorithms supported for JSON Web Token (JWT) signing
- * and verification.
- *
- * Defines a set of recognised algorithms including HMAC (HS*), RSA (RS*), and ECDSA (ES*) variants,
- * each with a specific SHA length (256, 384, or 512 bits). Provides methods to identify the
- * algorithm type and retrieve its properties.
- *
- * @author zihluwang
- */
-public enum Algorithm {
- HS256(1, 256, "HmacSHA256"),
- HS384(1, 384, "HmacSHA384"),
- HS512(1, 512, "HmacSHA512"),
- RS256(2, 256, "SHA256withRSA"),
- RS384(2, 384, "SHA384withRSA"),
- RS512(2, 512, "SHA512withRSA"),
- ES256(3, 256, "SHA256withECDSA"),
- ES384(3, 384, "SHA384withECDSA"),
- ES512(3, 512, "SHA512withECDSA");
-
- /**
- * Bit flag indicating an HMAC-based algorithm.
- */
- private static final int HS_FLAG = 1; // 001
-
- /**
- * Bit flag indicating an RSA-based algorithm.
- */
- private static final int RS_FLAG = 2; // 010
-
- /**
- * Bit flag indicating an ECDSA-based algorithm.
- */
- private static final int ES_FLAG = 3; // 011
-
- /**
- * The type flag identifying the algorithm family (HMAC, RSA, or ECDSA).
- */
- private final int typeFlag;
-
- /**
- * The length of the SHA hash in bits (256, 384, or 512).
- */
- private final int shaLength;
-
- /**
- * The standard name of the algorithm as recognised by the Java Cryptography Architecture (JCA).
- */
- private final String algorithm;
-
- /**
- * Constructs an algorithm enum constant with the specified type flag, SHA length, and algorithm name.
- *
- * @param typeFlag the bit flag identifying the algorithm type
- * @param shaLength the length of the SHA hash in bits
- * @param algorithm the JCA-compliant algorithm name
- */
- Algorithm(int typeFlag, int shaLength, String algorithm) {
- this.typeFlag = typeFlag;
- this.shaLength = shaLength;
- this.algorithm = algorithm;
- }
-
- /**
- * Determines whether this algorithm is HMAC-based.
- *
- * @return {@code true} if the algorithm uses HMAC (e.g., HS256, HS384, HS512), {@code false} otherwise
- */
- public boolean isHmac() {
- return (this.typeFlag & HS_FLAG) != 0;
- }
-
- /**
- * Determines whether this algorithm is RSA-based.
- *
- * @return {@code true} if the algorithm uses RSA (e.g., RS256, RS384, RS512), {@code false} otherwise
- */
- public boolean isRsa() {
- return (this.typeFlag & RS_FLAG) != 0;
- }
-
- /**
- * Determines whether this algorithm is ECDSA-based.
- *
- * @return {@code true} if the algorithm uses ECDSA (e.g., ES256, ES384, ES512), {@code false} otherwise
- */
- public boolean isEcdsa() {
- return (this.typeFlag & ES_FLAG) != 0;
- }
-
- /**
- * Retrieves the SHA length of this algorithm in bits.
- *
- * @return the SHA length (256, 384, or 512)
- */
- public int getShaLength() {
- return shaLength;
- }
-
- /**
- * Retrieves the type flag of this algorithm.
- *
- * @return the type flag (1 for HMAC, 2 for RSA, 3 for ECDSA)
- */
- public int getTypeFlag() {
- return typeFlag;
- }
-
- /**
- * Retrieves the JCA-compliant name of this algorithm.
- *
- * @return the algorithm name (e.g., "HmacSHA256", "SHA256withRSA")
- */
- public String getAlgorithm() {
- return algorithm;
- }
-}
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/HeaderClaims.java b/simple-jwt/src/main/java/com/onixbyte/jwt/constant/HeaderClaims.java
deleted file mode 100644
index cb681f7..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/HeaderClaims.java
+++ /dev/null
@@ -1,57 +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.constant;
-
-/**
- * Utility class defining standard header claim names for JSON Web Tokens (JWTs).
- *
- * Provides constants representing the recognised header claims as specified in the JWT standard.
- * These claims are used in the header section of a JWT to describe its structure and cryptographic
- * properties.
- *
- * @author zihluwang
- */
-public final class HeaderClaims {
-
- /**
- * Private constructor to prevent instantiation of this utility class.
- */
- private HeaderClaims() {
- }
-
- /**
- * The algorithm used to sign a JWT.
- */
- public static final String ALGORITHM = "alg";
-
- /**
- * The content type of the JWT.
- */
- public static final String CONTENT_TYPE = "cty";
-
- /**
- * The media type of the JWT.
- */
- public static final String TYPE = "typ";
-
- /**
- * The key ID of a JWT used to specify the key for signature validation.
- */
- public static final String KEY_ID = "kid";
-
-}
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/RegisteredClaims.java b/simple-jwt/src/main/java/com/onixbyte/jwt/constant/RegisteredClaims.java
deleted file mode 100644
index 6cf27a5..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/constant/RegisteredClaims.java
+++ /dev/null
@@ -1,92 +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.constant;
-
-import java.util.List;
-
-/**
- * Utility class defining standard registered claim names for JSON Web Tokens (JWTs).
- *
- * Provides constants representing the registered claims as defined in RFC 7519. These claims are
- * used in the payload section of a JWT to convey metadata about the token, such as its issuer,
- * subject, and validity period. All claims are optional but widely recognised in
- * JWT implementations.
- *
- * @author zihluwang
- */
-public final class RegisteredClaims {
-
- /**
- * Private constructor to prevent instantiation of this utility class.
- */
- private RegisteredClaims() {
- }
-
- /**
- * The "iss" (issuer) claim identifies the principal that issued the JWT.
- * Refer RFC 7529 Section 4.1.1
- */
- public static final String ISSUER = "iss";
-
- /**
- * The "sub" (subject) claim identifies the principal that is the subject of the JWT.
- * Refer RFC 7529 Section 4.1.2
- */
- public static final String SUBJECT = "sub";
-
- /**
- * The "aud" (audience) claim identifies the recipients that the JWT is intended for.
- * Refer RFC 7529 Section 4.1.3
- */
- public static final String AUDIENCE = "aud";
-
- /**
- * The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be
- * accepted for processing.
- * Refer RFC 7529 Section 4.1.4
- */
- public static final String EXPIRES_AT = "exp";
-
- /**
- * The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing.
- * Refer RFC 7529 Section 4.1.5
- */
- public static final String NOT_BEFORE = "nbf";
-
- /**
- * The "iat" (issued at) claim identifies the time at which the JWT was issued.
- * Refer RFC 7529 Section 4.1.6
- */
- public static final String ISSUED_AT = "iat";
-
- /**
- * The "jti" (JWT ID) claim provides a unique identifier for the JWT.
- * Refer RFC 7529 Section 4.1.7
- */
- public static final String TOKEN_ID = "jti";
-
- /**
- * An immutable list of all registered claim names defined in this class.
- *
- * Contains the values of {@link #ISSUER}, {@link #SUBJECT}, {@link #AUDIENCE},
- * {@link #EXPIRES_AT}, {@link #NOT_BEFORE}, {@link #ISSUED_AT}, and {@link #TOKEN_ID} for
- * convenient iteration or lookup.
- */
- public static final List
- * Holds the header, payload, and signature of a JWT as strings, typically in their Base64 URL-encoded
- * form as extracted from a token string. This record is used to facilitate parsing and processing
- * of JWTs without decoding or validating their contents.
- *
- * @param header the Base64 URL-encoded header string of the JWT
- * @param payload the Base64 URL-encoded payload string of the JWT
- * @param signature the Base64 URL-encoded signature string of the JWT
- * @author zihluwang
- */
-public record RawTokenComponent(
- String header,
- String payload,
- String signature
-) {
-}
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/holder/ObjectMapperHolder.java b/simple-jwt/src/main/java/com/onixbyte/jwt/holder/ObjectMapperHolder.java
deleted file mode 100644
index 28c5ff2..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/holder/ObjectMapperHolder.java
+++ /dev/null
@@ -1,78 +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.holder;
-
-import com.fasterxml.jackson.databind.MapperFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.json.JsonMapper;
-
-import java.util.Objects;
-
-/**
- * Singleton holder for a configured {@link ObjectMapper} instance.
- *
- * Provides a thread-safe, lazily initialised singleton to manage a single {@link ObjectMapper}
- * instance, configured to sort JSON properties alphabetically. This class is designed to ensure
- * consistent JSON serialisation and deserialisation across the application, particularly for
- * JSON Web Token (JWT) processing.
- *
- * @author zihluwang
- */
-public class ObjectMapperHolder {
-
- private static ObjectMapperHolder HOLDER;
-
- private final ObjectMapper objectMapper;
-
- /**
- * Private constructor to prevent instantiation of this utility class.
- */
- private ObjectMapperHolder() {
- this.objectMapper = JsonMapper.builder()
- .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
- .build();
- }
-
- /**
- * Retrieves the singleton instance of this holder.
- *
- * Uses double-checked locking to ensure thread-safe, lazy initialisation of the singleton. If
- * the instance has not been created, it is initialised in a synchronised block.
- *
- * @return the singleton {@link ObjectMapperHolder} instance
- */
- public static ObjectMapperHolder getInstance() {
- if (Objects.isNull(HOLDER)) {
- synchronized (ObjectMapperHolder.class) {
- if (Objects.isNull(HOLDER)) {
- HOLDER = new ObjectMapperHolder();
- }
- }
- }
- return HOLDER;
- }
-
- /**
- * Retrieves the configured {@link ObjectMapper} instance.
- *
- * @return the {@link ObjectMapper} configured for alphabetical property sorting
- */
- public ObjectMapper getObjectMapper() {
- return objectMapper;
- }
-}
diff --git a/simple-jwt/src/main/java/com/onixbyte/jwt/impl/HmacTokenCreator.java b/simple-jwt/src/main/java/com/onixbyte/jwt/impl/HmacTokenCreator.java
deleted file mode 100644
index f31e193..0000000
--- a/simple-jwt/src/main/java/com/onixbyte/jwt/impl/HmacTokenCreator.java
+++ /dev/null
@@ -1,121 +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.impl;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.onixbyte.jwt.TokenCreator;
-import com.onixbyte.jwt.TokenPayload;
-import com.onixbyte.jwt.constant.Algorithm;
-import com.onixbyte.jwt.constant.HeaderClaims;
-import com.onixbyte.jwt.holder.ObjectMapperHolder;
-import com.onixbyte.jwt.util.CryptoUtil;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.HashMap;
-
-/**
- * Implementation of {@link TokenCreator} that generates HMAC-signed JSON Web Tokens (JWTs).
- *
- * This class uses a specified HMAC algorithm to create signed tokens, incorporating a header,
- * payload, and signature. It ensures the secret key meets the minimum length requirement for
- * the chosen algorithm and handles JSON serialisation of the token components.
- *
- * @author zihluwang
- */
-public class HmacTokenCreator implements TokenCreator {
-
- private final Algorithm algorithm;
- private final String issuer;
- private final byte[] secret;
-
- private final ObjectMapper objectMapper;
-
- /**
- * Constructs an HMAC token creator with the specified algorithm, issuer, and secret key.
- *
- * Validates that the secret key length meets the minimum requirement for the chosen algorithm.
- *
- * @param algorithm the HMAC algorithm to use for signing (e.g., HS256, HS384, HS512)
- * @param issuer the issuer identifier to include in the token payload if not already present
- * @param secret the secret key as a string, used to generate the HMAC signature
- * @throws IllegalArgumentException if the secret key is shorter than the minimum required
- * length for the specified algorithm
- */
- public HmacTokenCreator(Algorithm algorithm, String issuer, String secret) {
- var _minSecretLength = algorithm.getShaLength() >> 3;
- var secretBytesLength = secret.getBytes(StandardCharsets.UTF_8).length;
- if (secretBytesLength < _minSecretLength) {
- throw new IllegalArgumentException("Secret key too short for HS%d: minimum %d bytes required, got %d."
- .formatted(algorithm.getShaLength(), _minSecretLength, secretBytesLength)
- );
- }
-
- this.algorithm = algorithm;
- this.issuer = issuer;
- this.secret = secret.getBytes(StandardCharsets.UTF_8);
- this.objectMapper = ObjectMapperHolder.getInstance().getObjectMapper();
- }
-
- /**
- * Creates and signs a JWT using the HMAC algorithm.
- *
- * Generates a token by encoding the header and payload as Base64 URL-safe strings,
- * creating an HMAC signature, and concatenating them with dots. If the payload does not
- * include an issuer, the configured issuer is added.
- *
- * @param payload the {@link TokenPayload} containing claims to include in the token
- * @return the signed JWT as a string in the format "header.payload.signature"
- * @throws IllegalArgumentException if the payload cannot be serialised to JSON due to
- * invalid data or structure
- * @throws RuntimeException if an unexpected error occurs during JSON processing
- */
- @Override
- public String sign(TokenPayload payload) {
- var header = new HashMap
- * This class integrates an {@link HmacTokenCreator} for signing tokens and an
- * {@link HmacTokenResolver} for verification and parsing, using a specified HMAC algorithm. It
- * supports converting token payloads to a custom type {@code T} via an {@link ObjectMapAdapter}.
- *
- * @param
- * Initialises the {@link TokenCreator} and {@link TokenResolver} with the provided HMAC
- * algorithm and secret key, and associates an adapter for converting token payloads to the
- * generic type {@code T}.
- *
- * @param algorithm the HMAC algorithm to use for signing and verification
- * @param issuer the issuer identifier to include in the token payload if not already present
- * @param secret the secret key as a string, used to sign and verify the HMAC signature
- * @param adapter the {@link ObjectMapAdapter} for converting payload maps to objects of
- * type {@code T}
- * @throws IllegalArgumentException if the secret key is too short for the specified algorithm
- */
- public HmacTokenManager(Algorithm algorithm, String issuer, String secret, ObjectMapAdapter
- * Retrieves the payload as a map and uses the configured {@link ObjectMapAdapter} to transform
- * it into the desired type.
- *
- * @param token the JWT string from which to extract the payload
- * @return the payload converted to an object of type {@code T}
- * @throws IllegalArgumentException if the token is malformed, the signature is invalid, or the
- * payload cannot be deserialised
- */
- @Override
- public T extract(String token) {
- var payloadMap = getPayload(token);
- return MapUtil.mapToObject(payloadMap, adapter);
- }
-
- /**
- * Signs a token payload to create a JWT.
- *
- * Delegates to the {@link TokenCreator} to generate a signed JWT string from the
- * provided payload.
- *
- * @param payload the {@link TokenPayload} containing claims to include in the token
- * @return the signed JWT as a string in the format "header.payload.signature"
- * @throws IllegalArgumentException if the payload cannot be serialised to JSON due to invalid
- * data or structure
- */
- @Override
- public String sign(TokenPayload payload) {
- return tokenCreator.sign(payload);
- }
-
- /**
- * Verifies the validity of a JWT.
- *
- * Delegates to the {@link TokenResolver} to check the token's signature and structure.
- *
- * @param token the JWT string to verify
- * @throws IllegalArgumentException if the token is malformed or the signature
- * verification fails
- */
- @Override
- public void verify(String token) {
- tokenResolver.verify(token);
- }
-
- /**
- * Retrieves the header claims from the provided JWT.
- *
- * Decodes the Base64-encoded header and deserialises it into a map of strings.
- *
- * @param token the JWT string from which to extract the header
- * @return a map containing the header claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the header cannot be
- * deserialised due to invalid JSON format
- */
- @Override
- public Map
- * Delegates to the {@link TokenResolver} to extract and deserialise the payload into a map,
- * excluding registered claims.
- *
- * @param token the JWT string from which to extract the payload
- * @return a map containing the custom payload claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the payload cannot
- * be deserialised
- */
- @Override
- public Map
- * This class splits a JWT into its components, verifies its signature using an HMAC algorithm, and
- * deserialises the header and payload into usable data structures. It ensures the secret key meets
- * the minimum length requirement for the specified algorithm.
- *
- * @author zihluwang
- */
-public class HmacTokenResolver implements TokenResolver {
-
- private final Algorithm algorithm;
- private final byte[] secret;
-
- private final ObjectMapper objectMapper;
-
- /**
- * Constructs an HMAC token resolver with the specified algorithm and secret key.
- *
- * Validates that the secret key length meets the minimum requirement for the chosen algorithm.
- *
- * @param algorithm the HMAC algorithm used for signature verification (e.g., HS256,
- * HS384, HS512)
- * @param secret the secret key as a string, used to verify the HMAC signature
- * @throws IllegalArgumentException if the secret key is shorter than the minimum required
- * length for the specified algorithm
- */
- public HmacTokenResolver(Algorithm algorithm, String secret) {
- var _minSecretLength = algorithm.getShaLength() >> 3;
- var secretBytesLength = secret.getBytes(StandardCharsets.UTF_8).length;
- if (secretBytesLength < _minSecretLength) {
- throw new IllegalArgumentException("Secret key too short for HS%d: minimum %d bytes required, got %d"
- .formatted(algorithm.getShaLength(), _minSecretLength, secretBytesLength)
- );
- }
-
- this.algorithm = algorithm;
- this.secret = secret.getBytes(StandardCharsets.UTF_8);
- this.objectMapper = ObjectMapperHolder.getInstance().getObjectMapper();
- }
-
- /**
- * Verifies the HMAC signature of the provided JWT.
- *
- * Splits the token into its components and uses the configured algorithm and secret to check
- * the signature's validity. If the signature does not match, an exception is thrown by the
- * underlying cryptographic utility.
- *
- * @param token the JWT string to verify
- * @throws IllegalArgumentException if the token is malformed or the signature verification
- * fails due to an invalid algorithm, key, or
- * mismatched signature
- */
- @Override
- public void verify(String token) {
- var _token = splitToken(token);
-
- var isValid = CryptoUtil.verifySignatureFor(algorithm,
- secret,
- _token.header(),
- _token.payload(),
- _token.signature().getBytes(StandardCharsets.UTF_8)
- );
- if (!isValid) throw new IllegalArgumentException(
- "JWT signature verification failed: the token may be tampered with or invalid.");
- }
-
- /**
- * Retrieves the header claims from the provided JWT.
- *
- * Decodes the Base64-encoded header and deserialises it into a map of strings.
- *
- * @param token the JWT string from which to extract the header
- * @return a map containing the header claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the header cannot be
- * deserialised due to invalid JSON format
- */
- @Override
- public Map
- * Decodes the Base64-encoded payload, deserialises it into a map, and removes any registered
- * claims as defined in {@link RegisteredClaims}.
- *
- * @param token the JWT string from which to extract the payload
- * @return a map containing the custom payload claims as key-value pairs
- * @throws IllegalArgumentException if the token is malformed or the payload cannot be
- * deserialised due to invalid JSON format
- */
- @Override
- public Map