diff --git a/CHANGELOG.md b/CHANGELOG.md index e7c56db..4a4303b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to `wp-rest-guard` will be documented in this file. +## v1.2.1 - 2024-02-26 + +- Allow the claims to be added to added to a generated JWT via filter. + ## v1.2.0 - 2024-02-22 - Add support for authenticated users interacting with the REST API. diff --git a/README.md b/README.md index a4e90c7..573f177 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # REST API Guard -Stable tag: 1.2.0 +Stable tag: 1.2.1 Requires at least: 6.0 diff --git a/plugin.php b/plugin.php index 7434adc..37d1098 100644 --- a/plugin.php +++ b/plugin.php @@ -321,8 +321,6 @@ function get_jwt_secret(): string { /** * Generate a JSON Web Token (JWT). * - * The JWT payload is intentionally not filtered to prevent - * * @param int|null $expiration The expiration time of the JWT in seconds or null for no expiration. * @param WP_User|int|null $user The user to include in the JWT or null for no user. * @return string @@ -349,6 +347,21 @@ function generate_jwt( ?int $expiration = null, WP_User|int|null $user = null ): $payload['sub'] = $user->ID; $payload['user_login'] = $user->user_login; + + /** + * Filter the additional claims to include in the JWT. + * + * The filer cannot modify any existing claims, only add new ones. + * + * @param array $additional_claims The additional claims to include in the JWT. + * @param WP_User|null $user The user to include in the JWT. + * @param array $payload The payload of the JWT. + */ + $additional_claims = apply_filters( 'rest_api_guard_jwt_additional_claims', [], $user, $payload ); + + if ( is_array( $additional_claims ) ) { + $payload = array_merge( $additional_claims, $payload ); + } } return JWT::encode( $payload, get_jwt_secret(), 'HS256' ); diff --git a/readme.txt b/readme.txt index e9e0902..0f8f867 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ === REST API Guard === -Stable tag: 1.2.0 +Stable tag: 1.2.1 Requires at least: 6.0 Tested up to: 6.3 Requires PHP: 8.0 diff --git a/tests/RestApiGuardTest.php b/tests/RestApiGuardTest.php index 2b523f0..2d87c2d 100644 --- a/tests/RestApiGuardTest.php +++ b/tests/RestApiGuardTest.php @@ -2,8 +2,10 @@ namespace Alley\WP\REST_API_Guard\Tests; use Firebase\JWT\JWT; +use Firebase\JWT\Key; use function Alley\WP\REST_API_Guard\generate_jwt; +use function Alley\WP\REST_API_Guard\get_jwt_secret; use const Alley\WP\REST_API_Guard\SETTINGS_KEY; @@ -281,4 +283,35 @@ public static function jwtDataProviderAuthenticated(): array { 'empty' => [ 'invalid', '' ], ]; } + + public function test_additional_jwt_claims() { + add_filter( + 'rest_api_guard_jwt_additional_claims', + function ( $claims, $user ) { + $claims['user_email'] = $user->user_email; + $claims['sub'] = 1234; + + return $claims; + }, + 10, + 2, + ); + + add_filter( 'rest_api_guard_user_authentication_jwt', fn () => true ); + + $user = static::factory()->user->create_and_get(); + + $token = generate_jwt( user: $user ); + + $this + ->with_header( 'Authorization', "Bearer {$token}" ) + ->get( '/wp-json/wp/v2/users/me' ) + ->assertOk(); + + // Ensure the additional claim is present. + $decoded = JWT::decode( $token, new Key( get_jwt_secret(), 'HS256' ) ); + + $this->assertEquals( $user->user_email, $decoded->user_email ); + $this->assertEquals( $user->ID, $decoded->sub ); // Ensure it cannot overwrite a claim. + } }