Capítulo 4
A Lógica de Callback (O Coração da Autenticação)
Após o utilizador ser validado no ACAPADEV ID, será reencaminhado de volta para a sua aplicação através da URL de Redirect que configurou.
Aqui está o código completo necessário para processar este regresso com segurança.
1. Adicionar as Rotas
No ficheiro routes/web.php da sua aplicação:
use Laravel\Socialite\Facades\Socialite;
use App\Http\Controllers\Auth\OAuthController;
// 1. Envia o utilizador para o ACAPADEV ID
Route::get('/auth/redirect', [OAuthController::class, 'redirect'])->name('oauth.redirect');
// 2. Recebe a resposta com o código de autorização
Route::get('/auth/callback', [OAuthController::class, 'callback'])->name('oauth.callback');
2. A Lógica Receção (Callback)
O ACAPADEV ID é agnóstico em relação ao seu backend. Crie um endpoint/rota que processa o Redirect e obtém o Token do utilizador. Abaixo encontra exemplos robustos em múltiplas tecnologias.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class OAuthController extends Controller
{
public function redirect()
{
return Socialite::driver('laravelpassport')->redirect();
}
public function callback()
{
try {
// Extrair os dados do ACAPADEV ID
$ssoUser = Socialite::driver('laravelpassport')->user();
// Dica RBAC: O ACAPADEV ID envia o cargo atribuído
$assignedRole = $ssoUser->user['app_role'] ?? null;
// 1. Procurar por utilizador com este SSO ID
$user = User::where('sso_id', $ssoUser->id)->first();
if (!$user) {
// 2. Se não encontrou pelo SSO ID, tenta pelo e-mail
$user = User::where('email', $ssoUser->email)->first();
if ($user) {
$user->update(['sso_id' => $ssoUser->id, 'avatar' => $ssoUser->avatar]);
} else {
// 3. Regista totalmente novo!
$user = User::create([
'name' => $ssoUser->name,
'email' => $ssoUser->email,
'sso_id' => $ssoUser->id,
'avatar' => $ssoUser->avatar,
'password' => null, // O SSO gere a senha
]);
}
}
// Sincronizar cargo localmente
if ($assignedRole === 'admin') {
$user->is_admin = true;
$user->save();
}
Auth::login($user, true);
return redirect()->intended('/dashboard');
} catch (\Exception $e) {
return redirect('/login')->with('error', 'Falha na autenticação via ACAPADEV ID.');
}
}
}
const express = require('express');
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2').Strategy;
const User = require('./models/User');
const app = express();
passport.use('acapadev', new OAuth2Strategy({
authorizationURL: 'https://id.acapadev.com/oauth/authorize',
tokenURL: 'https://id.acapadev.com/oauth/token',
clientID: process.env.ACAPADEV_CLIENT_ID,
clientSecret: process.env.ACAPADEV_CLIENT_SECRET,
callbackURL: 'https://sua-app.com/auth/callback'
},
async function(accessToken, refreshToken, profile, cb) {
try {
// Em Node.js precisará de fazer um GET extra a /api/user
// para buscar os detalhes do profile se o token não os incluir.
const response = await fetch('https://id.acapadev.com/api/user', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const ssoUser = await response.json();
let user = await User.findOne({ sso_id: ssoUser.id });
if (!user) {
user = await User.findOne({ email: ssoUser.email });
if (user) {
user.sso_id = ssoUser.id;
await user.save();
} else {
user = await User.create({
name: ssoUser.name,
email: ssoUser.email,
sso_id: ssoUser.id
});
}
}
return cb(null, user);
} catch (err) {
return cb(err, null);
}
}
));
app.get('/auth/redirect', passport.authenticate('acapadev'));
app.get('/auth/callback',
passport.authenticate('acapadev', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/dashboard');
}
);
Dicas de Prevenção de Erros
- Sempre confie no SSO: Se a conta foi revogada ou suspensa no Painel Super-Admin do ACAPADEV ID, a sua aplicação nem sequer recebe a resposta do Callback. O bloqueio é absoluto e imediato.
- Session Hijacking: Ao iniciar sessão, é sempre recomendado regenerar o ID da sessão do PHP com
$request->session()->regenerate();após oAuth::login(). O nosso exemplo utiliza o motor interno de Auth do Laravel que já faz isto parcialmente, mas para extrema segurança, adicione esse regenerador.
Integração Concluída! 🎉
A sua aplicação já faz parte do ecossistema centralizado ACAPADEV.