Mojolicious-Plugin-Kinde
view release on metacpan or search on metacpan
lib/Mojolicious/Plugin/Kinde.pm view on Meta::CPAN
package Mojolicious::Plugin::Kinde;
# ABSTRACT: A Mojo helper and route condition to extract Kinde auth header, verify JWT token, and return the claims
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::UserAgent;
use Mojo::JWT;
use Mojo::Exception;
our $VERSION = 'v0.0.2';
has jwt => undef;
has iss => '';
has audience => '';
sub register {
my ( $self, $app, $conf ) = @_;
my $jwks_url = $conf->{jwks_url} || $app->config->{kinde}->{jwks_url};
my $jwks_keys = Mojo::UserAgent->new->get($jwks_url)->result->json('/keys');
$self->jwt( Mojo::JWT->new( jwks => $jwks_keys ) );
$self->iss( $conf->{iss} || $app->config->{kinde}->{iss} );
$self->audience( $conf->{audience} || $app->config->{kinde}->{audience} );
$app->helper( get_kinde_claims => sub { _validate_auth_header( $self, @_ ) } );
$app->routes->add_condition( kinde_auth => sub { _validate_route( $self, @_ ) } );
} ## end sub register
sub _validate {
my ( $self, $c, $token ) = @_;
if ($token) {
my $token_data = $token ? $self->jwt->decode($token) : undef;
Mojo::Exception->throw('The token does not exist or is not valid') unless $token_data;
Mojo::Exception->throw('The `iss` claim does not match') unless $token_data->{iss} eq $self->iss;
Mojo::Exception->throw('The signature `alg` is not RS256') unless $self->jwt->algorithm eq 'RS256';
Mojo::Exception->throw('The expected audience is missing')
if $self->audience
&& ( scalar grep { $_ eq $self->audience } @{ $token_data->{aud} } ) == 0;
$c->stash->{kinde_user} = { id => $token_data->{'sub'} };
return $token_data;
} else {
return undef;
} ## end if ($token)
} ## end sub _validate
sub _validate_auth_header {
my ( $self, $c ) = @_;
my $headers = $c->req->headers;
my $auth = $headers->header('Authorization');
my $token = $auth ? ( split( ' ', $auth ) )[1] : undef;
return $self->_validate( $c, $token );
} ## end sub _validate_auth_header
sub _validate_route {
my ( $self, $route, $c, $captures, $arg ) = @_;
my $headers = $c->req->headers;
my $auth = $headers->header('Authorization');
my $token = $auth ? ( split( ' ', $auth ) )[1] : undef;
return $self->_validate( $c, $token ) ? 1 : 0;
} ## end sub _validate_route
1;
=pod
=encoding UTF-8
=head1 NAME
Mojolicious::Plugin::Kinde - A Mojo helper and route condition to extract Kinde auth header, verify JWT token, and return the claims
=head1 VERSION
version v0.0.1
=head1 SYNOPSIS
package MyApp;
use Mojo::Base 'Mojolicious';
sub startup {
my $self = shift;
$self->plugin( 'Mojolicious::Plugin::Kinde' ); # config can also be supplied here
$self->routes->get('/api')->requires( kinde_auth => {} );
}
...
# myapp_mojo.pl (config)
{
kinde => {
jwks_url => 'https://your-domain.kinde.com/.well-known/jwks.json',
iss => 'https://your-domain.kinde.com',
},
}
...
my $claims = $c->get_kinde_claims
=head1 DESCRIPTION
Mojolicious::Plugin::Kinde creates a helper method and a route condition. Both retrieve the JWT
token from the C<Authorization> header, verify the JWT, and do some sanity checks on the claims.
The C<get_kinde_claims> helper will return the claims extracted from the token.
The sanity checks include:
=over 4
=item confirm C<iss> claim matches the value from C<kinde> config
=item confirm the C<alg> is C<RS256>
=item confirm the C<aud> array contains the value from C<kinde> config (if not empty)
( run in 1.380 second using v1.01-cache-2.11-cpan-39bf76dae61 )