Last active
January 20, 2021 12:49
-
-
Save atatarn/34f4095961e4b5391b88 to your computer and use it in GitHub Desktop.
Google OpenIDConnect (OAuth 2.0 for Login) example with Mojolicious
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use Mojolicious::Lite; | |
use Mojo::Util qw(url_escape b64_decode); | |
use Mojo::JSON qw(from_json); | |
# Sample Google OAuth2 user email application using Mojolicious | |
# Based on the idea of https://gist.github.com/throughnothing/3726907 | |
# For more info see: | |
# https://developers.google.com/accounts/docs/OpenIDConnect | |
# https://developers.google.com/wallet/digital/docs/jwtdecoder | |
# | |
# Run this sample app with: | |
# morbo oauth.pl --listen http://*:5555 | |
my $config = plugin Config => { default => { | |
# Google OAuth API Key Values | |
# Get yours from: https://console.developers.google.com | |
client_id => '', | |
client_secret => '', | |
# Google OpenIDConnect Scope | |
scope => 'openid email', | |
# Google OAuth base uri | |
oauth_base => 'https://accounts.google.com/o/oauth2/auth', | |
oauth_token_service => 'https://www.googleapis.com/oauth2/v3/token', | |
# Application callback | |
cb => url_escape( 'http://mydomain.com:5555/oauth2callback' ), | |
cb_plain => 'http://mydomain.com:5555/oauth2callback', | |
}}; | |
get '/' => sub { shift->render( 'home' ) }; | |
get '/auth' => sub { | |
# Google Login Page URL construction | |
my $login_uri = "$config->{oauth_base}?client_id=$config->{client_id}&response_type=code&scope=$config->{scope}&redirect_uri=$config->{cb}"; | |
# You can append 'hd' parameter to force only users from our Google Hosted Domain to log in | |
# See 'hd' in https://developers.google.com/accounts/docs/OpenIDConnect#authenticationuriparameters | |
# Comment this line to allow user to use any of his Google Accounts | |
$login_uri .= '&hd=mydomain.com'; | |
shift->redirect_to($login_uri); | |
}; | |
# OAuth2 callback from google | |
get '/oauth2callback' => sub { | |
my $self = shift; | |
my $ua = $self->app->ua->post($config->{oauth_token_service} => form => { | |
code => $self->param('code'), | |
client_id => $config->{client_id}, | |
client_secret => $config->{client_secret}, | |
redirect_uri => $config->{cb_plain}, | |
grant_type => 'authorization_code' | |
}); | |
return $self->render(json => { error => 'Error getting tokens', debug => $ua->res->json }) unless $ua->res->is_status_class(200); | |
# Google OpenIDConnect response is a JWT string | |
# JWT contains header, claims and signature sections separated by dot - . | |
# Users' info is in second section (claims), presented as a base64 string withoud '=' in the end | |
my @tokens = split(/\./, $ua->res->json->{id_token}); | |
# Append extra characters to make original string base64 decodable | |
# See: https://github.com/googlewallet/jwt-decoder-python/blob/master/jwtdecoder.py | |
my $data = from_json(b64_decode($tokens[1].('=' x (4 - (length($tokens[1]) % 4))))); | |
# Resulting data: email, sub, hd (see: https://developers.google.com/accounts/docs/OpenIDConnect#obtainuserinfo ) | |
$self->render(json => { | |
email => $data->{email}, | |
email_verified => $data->{email_verified}, | |
sub => $data->{sub}, | |
hd => $data->{hd} ? $data->{hd} : 'Not in a Hosted Domain' | |
}); | |
}; | |
app->start; | |
__DATA__ | |
@@ home.html.ep | |
<a href='/auth'>Click here</a> to authenticate with Google OAuth. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment