Skip to main content

SAGE API 3.1, Laravel Socialite

Introducción

Hacía ya dos años y más que realice un trabajo para mi contabilidad que combinaba, WHMCS + SAGE + OVH + RedSys para así, ahorrarme más de 10000 apuntes al año.

Quería implementar Stripe, y de paso actualizar. Ay!!! Aquí vino el dolor. Desarrollos olvidados, tips y cosas que se quedan en el tintero. En su día, no había módulo de Laravel Socialite y todo lo que probé así que hice mi propia adaptación y todo iba bien en la actualización hasta que llegué aquí.

SAGE y OAuth 2

Instalar Socialite

Socialite es fácil de instalar.

composer require laravel/socialite

Después necesitamos el paquete de SAGE para Socialite (es muy simple y en caso de descontinuarse se puede continuar por uno mismo)

composer require socialiteproviders/sage

Importante leer el How to de ese módulo para entender que debemos configurar el listener que hay en EventServiceProvider con el fín de que Socialite escuche al módulo.

Comprobar las credenciales en SAGE

Esto me hizo perder el tiempo. Inexplicablemente pese a tener unas pocas modificaciones seguí manteniendo lo primordial, SAGE_CLIENT_ID, SAGE_CLIENT_SECRET, SAGE_REDIRECT_URL, SAGE_STATE_CSRF

Sin embargo tras llegar a la página de autentificación de SAGE (no encuentro en su doc que permita una autenticación stateless o sin servidor web) el retorno fallaba.

Primero lo achaque a que como he dockerizado mi contabilidad, uso localhost, en lugar de un FQDN como en mi vieja raspberry, donde usaba un dominio falso midominio.test.

Pero, revisando se me olvido (siempre se olvida algo) en la página de Sage Development Portal hay que configurar la app y entre otras cosas están los callbacks autorizados.

Asi que hay que añadirlo http://localhost/login/sage/callback

Pero volvió a fallar.

¿Uhmm? Raro se me hace. Revisé las variables, y sorpresa… el SAGE_ID_CLIENT Y EL SAGE_CLIENT_SECRET no corresponden a las que me funcionan en la vieja raspberry. Vamos que mi vieja contabilidad está trabajando con unos datos obsoletos o que pertenecen a otra cuenta.

En fin, ahora sí.

Cómo usarlo en pocos pasos

.env

Los datos de cliente son los de la página del portal de desarrolladores

SAGE_CLIENT_ID=Client ID 
SAGE_CLIENT_SECRET=’Client Secret’
SAGE_REDIRECT_URL=http://localhost/login/sage/callback
SAGE_STATE_CSRF=Token de al menos 32 caracteres aleatorio

Rutas

Es un ejemplo…

Route::get('/login/sage', [LoginController::class, 'redirectToSageProvider']);
Route::get('/login/sage/callback', [LoginController::class, 'handleProviderSageCallback']);

Controlador

En mi caso como hice mi propio paquete tengo un modelo en el que almaceno los tokens de proveedores externos de API que usan OAuth 2.0.

<?php

namespace App\Http\Controllers;

use Abkrim\ApiSage\Models\ExtToken;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Laravel\Socialite\Facades\Socialite;

class LoginController extends Controller
{
   public function handleProviderSageCallback()
   {
       $auth_token = Socialite::driver('sage')->user(); // Fetch authenticated user

       ExtToken::updateOrCreate(
           [ 'driver' => 'sage' ],
           [
               'type' => 'bearer',
               'scope' => 'full_access',
               'access' => $auth_token->token,
               'refresh' => $auth_token->refreshToken,
               'access_expires' => Carbon::now()->addSeconds($auth_token->expiresIn),
               'refresh_expires' => Carbon::now()->addSeconds($auth_token->accessTokenResponseBody['refresh_token_expires_in'])
           ]
       );

       return redirect()->to('/dondequeira');
   }

   public function redirectToSageProvider()
   {
       return Socialite::driver('sage')->redirect();
   }
}

Es curioso que el retorno me devuelva un objeto en el que puedo consultar todo menos el token de refresco que tengo que ir a por él en un objeto que es una array en el que establos mismo datos más ese token.

Espero que te sirva, si llegaste aquí, porque estas cosas no suelen estar escritas por ahí.

Aviso

Esta documentación y su contenido, no implica que funcione en tu caso o determinados casos. También implica que tienes conocimientos sobre lo que trata, y que en cualquier caso tienes copias de seguridad. El contenido el contenido se entrega, tal y como está, sin que ello implique ningún obligación ni responsabilidad por parte de Castris

Si necesitas soporte profesional puedes contratar con Castris soporte profesional.