🔏
OAuth2 Authentication
Some API providers implement the OAuth 2 Authorization Code Flow for authentication. Implementing this grant type every time you create a new API integration can be tedious and time-consuming. Saloon offers a simple, extendable OAuth2 framework to help you get up and running quickly.
Saloon has implemented the Authorization Code grant type since it is the most common OAuth2 flow. If you require any of the other grant types, please open a discussion on the GitHub repository.
Saloon has provided methods for the full Authorization Code grant.
$authConnector = new SpotifyAuthConnector;
// 1. Redirect the user to the authorization URL...
$authorizationUrl = $authConnector->getAuthorizationUrl($scopes, $state);
// 2. Handle the callback from the API provider and create an access token...
$authenticator = $authConnector->getAccessTokens($code, $state);
// 3. Authenticate your requests!
$spotify = new SpotifyConnector;
$request = new GetTracksRequest;
$request->authenticate($authenticator);
$spotify->send($request); // 🚀
// 4. Refresh your access tokens...
$newAuthenticator = $authConnector->refreshAccessTokens($authenticator);
This section of the documentation assumes that you are familiar with OAuth2 and specifically the Authorization Code Grant.
This feature has been heavily inspired by the “OAuth2 Client” package by “The PHP League” installed millions of times.
Let’s get started by preparing our Saloon connector ready to support the Authorization Code Flow. We recommend that you create a new connector in your integration just for authentication with the third-party provider. This can help keep the authentication and API code separate. Some providers may even have a separate OAuth2 server on a different subdomain to the API.
We strongly recommend that you create a new connector just for the OAuth2 flow.
<?php
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
use Saloon\Helpers\OAuth2\OAuthConfig;
use Saloon\Http\Connector;
class SpotifyAuthConnector extends Connector;
{
use AuthorizationCodeGrant;
}
After you have created the connector and added the trait, make sure to set the base endpoint to the URL of the OAuth2 server. For example:
<?php
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
use Saloon\Helpers\OAuth2\OAuthConfig;
use Saloon\Http\Connector;
class SpotifyAuthConnector extends Connector
{
use AuthorizationCodeGrant;
public function resolveBaseUrl(): string
{
return 'https://accounts.spotify.com';
}
}
Extend the defaultOauthConfig() method into your connector and start with setting your client ID, secret and redirect URI. You can also customise the various endpoints if the third party requires it.
<?php
use Saloon\Traits\OAuth2\AuthorizationCodeGrant;
use Saloon\Helpers\OAuth2\OAuthConfig;
use Saloon\Http\Connector;
class SpotifyAuthConnector extends Connector
{
use AuthorizationCodeGrant;
public function resolveBaseUrl(): string
{
return 'https://accounts.spotify.com';
}
protected function defaultOauthConfig(): OAuthConfig
{
return OAuthConfig::make()
->setClientId('my-client-id')
->setClientSecret('my-client-secret')
->setDefaultScopes(['user-read-currently-playing'])
->setRedirectUri('https://my-app.saloon.dev/auth/callback')
->setAuthorizeEndpoint('authorize')
->setTokenEndpoint('token')
->setUserEndpoint('user')
}
}
If your OAuth2 config is dependent on a per-user/tenant basis, you can modify the config after you have instantiated the connector.
<?php
$user = auth()->user(); // Your tenant/user.
$authConnector = new SpotifyAuthConnector;
// Overwrite the config just for this connector.
$authConnector->oauthConfig()->setClientId($user->spotify_client_id);
$authConnector->oauthConfig()->setClientSecret($user->spotify_client_secret);
Make sure to use the oauthConfig() method instead of accessing the property directly since it will not be set during instantiation of your class.
To generate an authorization URL, you can use the getAuthorizationUrl() method on the connector. Firstly instantiate the connector and then run the method. You can also provide scopes as well. It will also generate state for you if it has been provided.
<?php
$authConnector = new SpotifyAuthConnector;
$scopes = ['user-library-read'];
$authorizationUrl = $authConnector->getAuthorizationUrl($scopes, $state);
// Redirect the user to the URL...
To help prevent CSRF attacks, It’s highly recommended that you create a token in your authorization URL that you can confirm when the user redirects back to your application. This is known as state. Saloon will generate a 32-character alpha-numeric string for the state if you do not provide your own state.
You should generate the authorization URL first, then store the state securely. If you are using a framework like Laravel, you could store this state token in the user’s session.
<?php
$authConnector = new SpotifyAuthConnector;
$state = 'secret';
$authorizationUrl = $authConnector->getAuthorizationUrl($scopes, $state);
// Get the state, secure it somewhere like the session.
$state = $authConnector->getState(); // 'secret'
After the user has approved your application, the API provider will redirect you back to your application with an authorization code and state. This should be passed into your getAccessToken() method on your connector. If successful, the method will return an AccessTokenAuthenticator. This is a Saloon Authenticator that can be used to authenticate the rest of your requests.
<?php
$authConnector = new SpotifyAuthConnector;
$authenticator = $authConnector->getAccessTokens($code);
// ... Use authenticator in your other requests.
The method will return an AccessTokenAuthenticator. This is a Saloon Authenticator that can be used to authenticate the rest of your requests. Click here to read more about using authenticators.
As mentioned above, if you stored the state that was generated during creating an authorization url, you should pass this expected state alongside the state sent back by the API provider's OAuth2 server.
<?php
$authConnector = new SpotifyAuthConnector;
// It will throw an exception if the state and expected state don't match,
// but both must be present.
$authenticator = $authConnector->getAccessTokens($code, $state, $expectedState);
You will likely need to store the authenticator securely against a user, like in an encrypted field in the database. You may serialise and unserialise the authenticator using the helper methods below.
<?php
$authConnector = new SpotifyAuthConnector;
$authenticator = $authConnector->getAccessTokens($code);
$serialized = $authenticator->serialize(); // Securely store this against your user.
$authenticator = AccessTokenAuthenticator::unserialize($serialized); // You can unserialize it too.
If you are using Laravel Eloquent, you can use the EncryptedOAuthAuthenticatorCast / OAuthAuthenticatorCast casts to automatically cast the authenticator for storing into your database.
After you have created the access tokens above, you should have an AccessTokenAuthenticator. This class can be used to authenticate your other connectors/requests with the access token you have just received. Just use the authenticate() method on either your request or your connector.
<?php
$authConnector = new SpotifyAuthConnector;
$authenticator = $authConnector->getAccessTokens($code);
$connector = new SpotifyApiConnector;
$request = new CurrentSongRequest;
$request->authenticate($authenticator);
$response = $connector->send($request);
// Or you can authorize the whole connector
$connector = new SpotifyApiConnector;
$connector->authenticate($authenticator);
// Make requests...
Before using the authenticator, you should always check if the access token has expired and if it needs refreshing. When you need to refresh access tokens, you can call the refreshAccessToken() method which will create a fresh authenticator.
<?php
$authenticator = $user->auth; // Your authenticator class.
// Check if the authenticator has expired, if it has - we can refresh
// the access token.
if ($authenticator->hasExpired() === true) {
$authConnector = new SpotifyAuthConnector;
$authenticator = $authConnector->refreshAccessToken($authenticator);
$user->auth = $authenticator;
$user->save();
}