Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow additional claims to be added to the JWT #20

Merged
merged 2 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# REST API Guard

Stable tag: 1.2.0
Stable tag: 1.2.1

Requires at least: 6.0

Expand Down
17 changes: 15 additions & 2 deletions plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<string, mixed> $additional_claims The additional claims to include in the JWT.
* @param WP_User|null $user The user to include in the JWT.
* @param array<string, mixed> $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' );
Expand Down
2 changes: 1 addition & 1 deletion readme.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
33 changes: 33 additions & 0 deletions tests/RestApiGuardTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
}
}