A tale of Trello and Laravel Socialite
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.
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
.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();
All that sounded fine, I won’t have to spend time on the provider-specific OAuth implementations, lets go!
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.
I stumbled over two things:
- GitHub returned no
expires_inbecause the tokens apparently never expire, I had to accommodate for that.
- 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
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.
What a ride.. Trello, seriously, please implement OAuth2