Dancer2-Plugin-JWT

 view release on metacpan or  search on metacpan

lib/Dancer2/Plugin/JWT.pm  view on Meta::CPAN


    if ( exists $config->{need_nbf} && defined $config->{need_nbf} ) {
        $need_nbf = $config->{need_nbf};
    }

    if ( exists $config->{need_exp} && defined $config->{need_exp} ) {
        $need_exp = $config->{need_exp};
    }

    if ( exists $config->{need_leeway} && defined $config->{need_leeway} ) {
        $need_leeway = $config->{need_leeway};
    }

    $dsl->app->add_hook(
        Dancer2::Core::Hook->new(
            name => 'before_template_render',
            code => sub {
                my $tokens = shift;
                $tokens->{jwt} = $dsl->app->request->var('jwt');
            }
        )
    );

    $dsl->app->add_hook(
        Dancer2::Core::Hook->new(
            name => 'after',
            code => sub {
                if ($expose_authorization_header) {
                    my $response = shift;
                    $response = $response->isa('Dancer2::Core::Response') ? $response : $response->response;
                    $response->push_header('Access-Control-Expose-Headers' => 'Authorization');
                }
            }
        )
    );

    $dsl->app->add_hook(
        Dancer2::Core::Hook->new(
            name => 'before',
            code => sub {
                my $app = shift;
                my $encoded = $app->request->headers->authorization;

                if( defined $encoded ) {
                    # Remove "Bearer " (sic) from the beginning of the Authorization header if present.
                    # "Bearer" signifies the schema and should be present
                    # but due to backwards compatibility we support also without it.
                    # https://jwt.io/introduction/ (How do JSON Web Tokens work?)
                    $encoded =~ m/^ (?: Bearer [[:space:]]{1} | ) (?<token> [^[:space:]]{0,} ) $/msx;
                    $encoded = $+{token};
                }

                if ($set_cookie_header && $app->request->cookies->{_jwt}) {
                    $encoded = $app->request->cookies->{_jwt}->value ;
                }
                elsif ($app->request->param('_jwt')) {
                    $encoded = $app->request->param('_jwt');
                }

                if ($encoded) {
                    my $decoded;
                    eval {
                        $decoded = decode_jwt( token        => $encoded,
                                               key          => $secret,
                                               verify_iat   => $need_iat,
                                               verify_nbf   => $need_nbf,
                                               verify_exp   => defined $need_exp ? 1 : 0 ,
                                               leeway       => $need_leeway,
                                               accepted_alg => $alg,
                                               accepted_enc => $enc );
                    };
                    if ($@) {
                        $app->execute_hook('plugin.jwt.jwt_exception' => ($a = $@));  # this is weird, but required!
                    };
                    $app->request->var('jwt', $decoded);
                    $app->request->var('jwt_status' => 'present');

                }
                else {
                    ## no token
                    $app->request->var('jwt_status' => 'missing');
                }
            }
        )
    );

    $dsl->app->add_hook(
        Dancer2::Core::Hook->new(
            name => 'after',
            code => sub {
                my $response = shift;
                my $decoded = $dsl->app->request->var('jwt');
                if($set_authorization_header || $set_cookie_header || $set_location_header) {
                    # If all are disabled, then skip also encoding!
                    if (defined($decoded)) {
                        my $encoded = encode_jwt( payload      => $decoded,
                                                  key          => $secret,
                                                  alg          => $alg,
                                                  enc          => $enc,
                                                  auto_iat     => $need_iat,
                                                  relative_exp => $need_exp,
                                                  relative_nbf => $need_nbf );

                        if($set_authorization_header) {
                            $response->headers->authorization($encoded);
                        }

                        if($set_cookie_header) {
                            my %cookie =  (
                                value     => $encoded,
                                name      => '_jwt',
                                expires   => time + ($need_exp // $fourWeeks),
                                path      => '/',
                                http_only => 0);
                            $cookie{domain} = $cookie_domain if defined $cookie_domain;
                            $response->push_header('Set-Cookie'
                                => Dancer2::Core::Cookie->new(%cookie)->to_header());
                        }

                        if ($set_location_header && $response->status =~ /^3/) {
                            my $u = URI->new( $response->header('Location') );
                            $u->query_param( _jwt => $encoded);
                            $response->header(Location => $u);
                        }
                    }
                } # ! $set_authorization_header && ! $set_cookie_header && ! $set_location_header
            }
        )
    );
};



register_plugin;

1;

=encoding UTF-8

=head1 NAME

Dancer2::Plugin::JWT - JSON Web Token made simple for Dancer2

=head1 SYNOPSIS

     use Dancer2;
     use Dancer2::Plugin::JWT;

     post '/login' => sub {
         if (is_valid(param("username"), param("password"))) {
            jwt { username => param("username") };
            template 'index';
         }
         else {
             redirect '/';
         }



( run in 0.684 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )