Mojolicious plugin to make it a little easier to implement an OAuth2 authorization/resource server
Clone or download
leejo prevent double escaping of return URL in oauth2_auth_request helper
it seems recent changes to Mojolicious[1] cause the following to double
escape the URL when the access token contains = char:

	$mojo_url->fragment( $params->to_string );


    OAuth2::Server: ===> access_token=MTUyNTE3OTE2OC00NDYwOS0wLjM3OTk3MTYyNjMyNjcxMS1SYjVoV2F1WlExNGJjSnNaM3RPM1JoM0MzMndvTzQ%3D&token_type=...
    OAuth2::Server: ===> https://client/cb#access_token=MTUyNTE3OTE2OC00NDYwOS0wLjM3OTk3MTYyNjMyNjcxMS1SYjVoV2F1WlExNGJjSnNaM3RPM1JoM0MzMndvTzQ%253D&token_type=...

that was debug for `$params->to_string` and `$mojo_url` - notice how the
%3D gets escaped *again* to %253D

so we have to call url_unescape on $params->to_string prior to passing
it into $mojo_url->fragment otherwise we get. possibly there is another
way to construct this fragment without having to pass in
$param->to_string, to investigate

[1] possibly kraih/mojo/commit/777f24f141d2b286337e5813b1282021c5dc111a
although can't be sure without a bisect
Latest commit ea7023c May 1, 2018


Mojolicious::Plugin::OAuth2::Server - Easier implementation of an OAuth2 Authorization Server / Resource Server with Mojolicious

<a href=''><img src='' alt='Build Status' /></a>
<a href=''><img src='' alt='Coverage Status' /></a>




use Mojolicious::Lite;

plugin 'OAuth2::Server' => {
    ... # see SYNOPSIS in Net::OAuth2::AuthorizationServer::Manual

group {
  # /api - must be authorized
  under '/api' => sub {
    my ( $c ) = @_;

    return 1 if $c->oauth; # must be authorized via oauth

    $c->render( status => 401, text => 'Unauthorized' );
    return undef;

  any '/annoy_friends' => sub { shift->render( text => "Annoyed Friends" ); };
  any '/post_image'    => sub { shift->render( text => "Posted Image" ); };

any '/track_location' => sub {
  my ( $c ) = @_;

  my $oauth_details = $c->oauth( 'track_location' )
      || return $c->render( status => 401, text => 'You cannot track location' );

  $c->render( text => "Target acquired: @{[$oauth_details->{user_id}]}" );


Or full fat app:

use Mojo::Base 'Mojolicious';


sub startup {
  my $self = shift;


  $self->plugin( 'OAuth2::Server' => $oauth2_auth_code_grant_config );

Then in your controller:

 sub my_route_name {
   my ( $c ) = @_;

   if ( my $oauth_details = $c->oauth( qw/required scopes/ ) ) {
     ... # do something, user_id, client_id, etc, available in $oauth_details
   } else {
     return $c->render( status => 401, text => 'Unauthorized' );



This plugin implements the various OAuth2 grant types flow as described at It is a complete implementation of RFC6749, with the exception of the "Extension Grants" as the description of that grant type is rather hand-wavy.

The bulk of the functionality is implemented in the Net::OAuth2::AuthorizationServer distribution, you should see that for more comprehensive documentation and examples of usage.

The examples here use the "Authorization Code Grant" flow as that is considered the most secure and most complete form of OAuth2.



Registers the plugin with your app - note that you must pass callbacks for certain functions that the plugin expects to call if you are not using the plugin in its simplest form.

$self->register($app, \%config);

Registering the plugin will call the Net::OAuth2::AuthorizationServer and create a auth_code_grant that can be accessed using the defined authorize_route and access_token_route. The arguments passed to the plugin are passed straight through to the auth_code_grant method in the Net::OAuth2::AuthorizationServer module.


Checks if there is a valid Authorization: Bearer header with a valid access token and if the access token has the requisite scopes. The scopes are optional:

unless ( my $oauth_details = $c->oauth( @scopes ) ) {
  return $c->render( status => 401, text => 'Unauthorized' );

This calls the Net::OAuth2::AuthorizationServer::AuthorizationCodeGrant module (verify_token_and_scope method) to validate the access/refresh token.


This is a helper to allow you get get the redirect URI instead of directing a user to the authorize_route - it requires the details of the client:

my $redirect_uri = $c->oauth2_auth_request({
  client_id     => $client_id,
  redirect_uri  => 'https://foo',
  response_type => 'token',
  scope         => 'list,of,scopes',
  state         => 'foo=bar&baz=boz',

if ( $redirect_uri ) {
 # do something with $redirect_uri
} else {
  # something didn't work, e.g. bad client, scopes, etc

You can use this helper instead of directing a user to the authorize_route if you need to do something more involved with the redirect_uri rather than having the plugin direct to the user to the resulting redirect uri


Net::OAuth2::AuthorizationServer - The dist that handles the bulk of the functionality used by this plugin


Lee Johnson -

With contributions from:

Nick Logan




This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. If you would like to contribute documentation or file a bug report then please raise an issue / pull request: