A tale of Trello and Laravel Socialite

A tale of Trello and Laravel Socialite
Photo by Ybrayym Esenov / Unsplash

While recently working on my small-scale project management application “Flow” I had two features in mind: Third-Party Authentication and a tool to import Trello Boards into my database

Introducing Laravel Socialite

Laravel Socialite is officially listed in the laravel documentation as a simple way to authenticate using OAuth providers

Laravel Socialite provides an expressive, fluent interface to OAuth authentication with Facebook, Twitter, Google, LinkedIn, GitHub, GitLab and Bitbucket. It handles almost all of the boilerplate social authentication code you are dreading writing.

From https://github.com/laravel/socialite

Scolling through the huge list of supported providers, I immediately found GitHub, GitLab, Gitea and Trello, great!

But I also wanted users to be able to configure the third-party apps through the UI, not by setting config.php or .env variables. Luckily, socialite provides a simple way to set a provider config programmatically:

$config = new \SocialiteProviders\Manager\Config("client_id", "secret", "http://yourdomain.com/api/redirect");
return Socialite::driver('github')->setConfig($config)->redirect();

https://socialiteproviders.com/usage/#overriding-a-config

All that sounded fine, I won’t have to spend time on the provider-specific OAuth implementations, lets go!

The Good

Getting started with GitHub, GitLab and Gitea is as simple as running

composer require socialiteproviders/github

and adding the corresponding socialite event listener. I also had to add a config.php entry for each provider even though I would override the setting later on, but they are allowed to be empty.

The Bad

I stumbled over two things:

  1. GitHub returned no refresh_token and no expires_in because the tokens apparently never expire, I had to accommodate for that.
  2. Socialite does handle the OAuth grant flow, but it does not offer refreshing tokens.

The latter is in some way understandable since socialite is more targeted towards simply authenticating the user and not actually using the tokens returned by the grant. Since I planned on actually using the tokens later on, I implemented a simple “get the token, check if it is expired, if it is refresh it and save the new tokens” function

What bothered me the most while implementing the refresh feature was that I had to hard-code the api urls (or add redundant config entries) since the providers do not offer any way to access the urls in the providers.

I also assumed that the json returned from the refresh endpoints of each provider has the same keys which luckily was the case for the three git providers that follow a standardized schema.

Every OAuth provider I worked with in the past worked in a similar way: you log in with your account, go to your profile settings and create a new OAuth application by specifying a redirect uri and you receive a client_id and client_secret

So I logged into my Trello account and searched in the settings… nothing

I switched to the atlassian account settings because in reality, a trello account is an atlassian account… nothing

RTFM: Trello API introduction

To get started, you’ll need an API key. You can get your API key by logging into Trello and visiting https://trello.com/app-key

Okay, so I navigated to the link hidden in the documentation — et voilá: we get an API key. One API key. Per Account.

Because the API key is tied to the user, it is often a good idea to create a Trello user specifically for building a single application or integration. This ensures that a third-party’s integration is disassociated from a third-party integration’s developer’s Trello account.

Alright. I’ll do that later, let’s just get it working in my app.

The hell of Socialite and OAuth 1

For those wondering: Yes, Trello only offers basic OAuth 1.0, not the widely spread OAuth 2, socialite has it implemented, but now to the fun part:

An unknown application

The authentication page calls the app “An unknown application” because guess what, “flow” has 4 characters and the minimum is 5 🤦‍♂️ This isn’t documented anywhere.

Dynamic config? Nope

Not only did the setConfig function of socialite fail to set the trello provider config, it also loudly complained that the values in config.php are empty, so I had to make them placeholder strings.

The reason why setConfig does not work is because the OAuth1 server implementation uses an internal clientCredentials object that gets loaded from the config.php but is then completely independent from the config option modified by the setConfig function.

Because the clientCredentials object is protected I had to extend the Trello socialite provider so I can a) change the “name” to a 5 character one and b) modify the internal credentials

Last but not least: Hashtag #Hashtag

If you click the “deny” button in the authenticate screen, you are redirected to the specified redirect url with an error attached. All other applications pass the error as a get parameter so the server can read what went wrong. Trello gives you the error appended as hash which means the server can’t access it.

https://my.application.com/oauth/trello#token=&error=Token%20request%20rejected

What a ride.. Trello, seriously, please implement OAuth2