Building on the excellent answers from @Samphors and @Muffy, here is how you would do this in the MVC world of Symfony
My controller...
class GMailController extends AbstractController
{
/**
* @Route("/g/mail", name="app_g_mail")
*/
public function index(Request $request): Response
{
$code = $request->query->get('code');
return $this->render('g_mail/index.html.twig', [
'controller_name' => 'GMailController',
'code' => $code
]);
}
/**
* @Route("/g/mail/test", name="app_g_mail_test", methods={"POST"})
*/
public function test(Request $request) : Response
{
$filepath = '../client_secret.json';
$contents = file_get_contents($filepath);
$client = new Client();
$client->setApplicationName('Gmail_test');
$client->setAuthConfigFile($filepath);
$client->addScope('email');
$client->addScope('https://mail.google.com');
$client->setRedirectUri('https://localhost:8005/g/mail');
$client->setAccessType('offline');
// Redirect the URL after OAuth
$code = $request->request->get('code');
if ($code) {
error_log('code is set = '.$code);
$client->authenticate($code);
$_SESSION['access_token'] = $client->getAccessToken();
}
// If Access Toket is not set, show the OAuth URL
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
error_log('setting access token');
$client->setAccessToken($_SESSION['access_token']);
} else {
error_log('creating authorization url');
$authUrl = $client->createAuthUrl();
error_log($authUrl);
return new JsonResponse(['success' => true, 'authUrl' => $authUrl]);
}
if ($client->getAccessToken()) {
$_SESSION['access_token'] = $client->getAccessToken();
// Prepare the message in message/rfc822
try {
$service = new Gmail($client);
$optParams = [];
$optParams['maxResults'] = 5; // Return Only 5 Messages
$optParams['labelIds'] = 'INBOX'; // Only show messages in Inbox
$messages = $service->users_messages->listUsersMessages('me',$optParams);
$list = $messages->getMessages();
$messageId = $list[0]->getId(); // Grab first Message
$optParamsGet = [];
$optParamsGet['format'] = 'full'; // Display message in payload
$message = $service->users_messages->get('me',$messageId,$optParamsGet);
$messagePayload = $message->getPayload();
$headers = $message->getPayload()->getHeaders();
$parts = $message->getPayload()->getParts();
$body = $parts[0]['body'];
$rawData = $body->data;
$sanitizedData = strtr($rawData,'-_', '+/');
$decodedMessage = base64_decode($sanitizedData);
return new JsonResponse(['success' => true, 'message' => $decodedMessage]);
} catch(Exception $e) {
error_log('in exception handler');
error_log($e);
return new JsonResponse(['success' => false, 'error' => $e->__toString()]);
}
}
return new JsonResponse(['success' => false]);
}
}
My twig template...
{% extends 'base.html.twig' %}
{% block title %}GMail API Bench{% endblock %}
{% block body %}
<div class="container m-5">
<div class="row my-2">
<div class="col-12">
<button type="button" class="btn btn-primary btn-lg" id="test-gmail-button">Test GMail API</button>
</div>
</div>
<div class="row my-2">
<h4><b>Authorization:</b></h4>
<div id="test-authorization">
<a id="authorization-link" href="#"></a>
</div>
<input type="hidden" id="gmail-authorization-code" value="{{ code }}">
{% if code is not null %}
<span class="text-success"><h4>Authorized</h4></span>
{% endif %}
</div>
<div class="row my-2">
<h4><b>Results:</b></h4>
<div id="test-results">
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script src="/static/site/js/gmail_bench.js?v=1.20230126"></script>
{% endblock %}
My client-side JavaScript...
$(document).ready(() => {
console.log('gmail_bench.js: in document ready')
})
$('#test-gmail-button').on('click', function(ev) {
console.log('test gmail');
let code = $('#gmail-authorization-code').val();
$.ajax({
url: '/g/mail/test',
type: 'POST',
data: {
code: code
},
success: function(data, textStatus) {
if(data.success) {
if(data.authUrl) {
$('#authorization-link').attr('href',data.authUrl);
$('#authorization-link').html('Authorize');
}
if(data.message) {
$('#test-results').empty().append(data.message);
}
} else {
$('#test-results').empty().append(data.error);
}
},
error: function(xhr, textStatus) {
console.log('in test gmail error');
console.log(xhr);
console.log(textStatus);
}
})
})
So the way this works is the first post to the test endpoint returns the authorization url. This is added as a link on the page...

Then after authorization, the OAuth2 code is added to the page...

Finally the second click on test butter sends the code and the email contents come back...
