How to upgrade API to OAuth2 with Guzzle

Found a typo? Edit me
This post is deprecated since November 2022. Its knowledge is old and should not be used.

The API has changed to a paywall now. Also the REST API was changed to GraphQL and there is no documentation about endpoints of meetups by groups. The visit rate of page is also 3-5 people a day. For there reasons, it does not make sense to maintain this page anymore, so I've sunset it.

I got an email from 5 days ago, that basically every API request will be paid since August 15, 2019. $ 30/month, that's like my phone bill.

95 % of data on Friends Of Php depend on API - updated daily. The website is free, so it might kill the content or I'd have to move to crawlers and hope for the lack of protection on against them.

Unless we use Oauth2 before August 15. I never used it, but how hard that can be, right?

There is no information about API upgrade on their blog, so I'll share the email to give you an idea:

Documentation vs. Code

This is a simple task, that in the end has simple 15 lines of new code. But documentation turned it into almost 3 hours of work.

It seems like OAuth2 must be something very new, because Guzzle supports only Oauth (1). If the last commit in 2014 can be called "supports".

After a bit of Googling if found kamermans/guzzle-oauth2-subscriber. I tried to copy-paste the code

Choose Your Path

Fuck-up #1: Put Oldest First

Why would you put the newest content first, right? You know, like on Twitter, Facebook, basically any news, messages...

If you write a code that other people read, you should read The Design of Everyday Things or Don't Make Me Think

So now you can imagine I'm using the latest Guzzle 6 and trying to implement a solution for Guzzle 4 & 5.

👍 Rule of the thumb: put news and important information first.

Fuck-up #2: Support All Versions

Fuck-Up #1 is a natural consequence of trying to support multiple versions at one branch/tag. Instead of putting all code to one branch, let always the last branch support the latest LTS dependencies.

What does that mean?

Let's look at Symfony repository. Instead of "Symfony" imagine any package that is version. Now there is Symfony 4, so there was version 3, 2, 1 in the past. Like Guzzle 6, 5, 4...

Now you've decided to upgrade and look for (because you haven't heard about Rector yet):

But how do you upgrade from Symfony 3? In the latest branch, there is always context-aware information. Do you need any older version? Switch to branch 3.x or 2.x.

I love this, because it focuses on mainstream, providing minimal needed data, but also allows the same for minorities.

The Symfony docs does the same:

I wrote about this in detail in What can You Learn from Menstruation post.

👍 Rule of the thumb: never mix 2 major versions in one branch, unless LTS framework

Fuck-up #3: Provide more solutions

After I figured out the README is not text for programmers but for detectives, I've found the code with middleware I though I was looking for:


$oauth = new OAuth2Middleware($grant_type);

$stack = HandlerStack::create();

$client = new Client([
    'auth'     => 'oauth',
    'handler'  => $stack,

This supposes to work... but instead I got as useless exceptions as "cannot authenticate". After 60 minutes of trying, I went to sleep with frustration.

In the morning I've noticed little note:

Tried it and it worked. WTF? Why there is a broken code first, then "working alternative" second?

This is a common problem with double complexity = exponential bugs. If you translate your website to English and German, it will have more translation bugs than the English-only version. Of course, German might be important to your business, but the alternative code has as little added value as having a website in American English and British English.

👍 Rule of the thumb: don't create alternatives for mainstream, it mostly confuses people. People will always find alternatives themselves

How to Write Perfect Documentation?

It's important to know, that I don't try to make this about the specific documentation, but rather about any open-source documentation and how it's written.

If I'd be sending an invoice to my employer, it would look like this:

How to Lower Those 2,5 hours to 15 minutes?

Let's pause a bit and think - what do we really need, when we use the package for the first time?

If we agree on these as our priorities, then all we need is working piece of code.

Be Sure the Code Works without Testing it

How do we know the code is working?

Instead of having documentation with text (= "weak strings"), the best would be:

That's the perfect documentation, because we can skip the verification and detective part and trust it by validated contract.

Now finally to the solution ↓

5 Steps to Guzzle Oauth2

composer require guzzlehttp/guzzle:^6.3
composer require kamermans/guzzle-oauth2-subscriber
<?php declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use GuzzleHttp\Client;
use kamermans\OAuth2\GrantType\ClientCredentials;
use kamermans\OAuth2\OAuth2Middleware;

// get these here:
$meetupComOauth2Key = '123';
$meetupComOauth2Secret = 'ABC';

// boilerplate code for Oauth2
$oAuth2Client = new Client([
    // URL for access_token request
    'base_uri' => '',

$oAuth2Config = [
    'client_id' => $meetupComOauth2Key,
    'client_secret' => $meetupComOauth2Secret,
$clientCredentials = new ClientCredentials($oAuth2Client, $oauthConfig);
$oAuth2Middleware = new OAuth2Middleware($clientCredentials);

// the main code
$client = new Client();

// call anything
$response = $client->request('GET', '...');

But does it still work?

Happy coding!

Have you find this post useful? Do you want more?

Follow me on Twitter, RSS or support me on GitHub Sponsors.