Adding "Sign in with EduSpaze" to your app
For a vendor — Zoala's Laravel staff app and React pupil app are the example — this is all it takes for pupils and staff to arrive from EduSpaze already signed in. It is standard OpenID Connect, so your existing libraries do the work. Contract: §11 of the vendor integration guide.
1. Register
Startup portal → Integration → Sign in with EduSpaze:
- Redirect address:
https://app.zoala.co/auth/eduspaze/callback - Sign-in start address:
https://app.zoala.co/auth/eduspaze
Copy the client ID and secret into your server's environment: EDUSPAZE_CLIENT_ID, EDUSPAZE_CLIENT_SECRET.
2. Staff web app (Laravel + Socialite)
Use the community OpenID Connect provider for Socialite (socialiteproviders/manager with a generic OIDC provider), pointed at discovery:
// config/services.php
'eduspaze' => [
'base_url' => 'https://www.eduspazeconnect.com', // discovery: /.well-known/openid-configuration
'client_id' => env('EDUSPAZE_CLIENT_ID'),
'client_secret' => env('EDUSPAZE_CLIENT_SECRET'),
'redirect' => 'https://app.zoala.co/auth/eduspaze/callback',
],
// routes/web.php
Route::get('/auth/eduspaze', fn () => Socialite::driver('eduspaze')->scopes(['openid', 'email', 'profile'])->redirect());
Route::get('/auth/eduspaze/callback', function () {
$who = Socialite::driver('eduspaze')->user(); // verifies the ID token
$raw = $who->getRaw(); // tenant, subject, role, preferred_username …
$user = User::where('email', $raw['preferred_username'] ?? $who->getEmail())->firstOrFail();
Auth::login($user);
request()->session()->regenerate();
return $raw['role'] === 'student'
? redirect()->away(pupilAppHandOff($user)) // see 3
: redirect('/app/dashboard/school/overview');
});
3. Pupil app (React)
The pupil app keeps its sign-in in the browser on its own site, so the server hands it over once, the same way the password sign-in does:
function pupilAppHandOff(User $user): string {
$code = Str::random(48);
Cache::put('eduspaze-handoff:'.hash('sha256', $code), $user->id, now()->addMinute());
return 'https://www.student.zoala.co/eduspaze?code='.$code;
}
// POST /api/app/mobile/login/eduspaze {code} → the same answer as /api/app/mobile/login (Cache::pull: single use)
// <Route path="/eduspaze" element={<EduSpazeLogin />} /> — exchanges the code, stores the token, opens /home
(The same small page as in Building the one-time sign-in link, §2b.)
4. Try it
Sign in to EduSpaze as a pupil who has Zoala, open Zoala from the launcher: EduSpaze sends you to /auth/eduspaze, Zoala sends you to EduSpaze, EduSpaze sends you straight back with a code, and you land on Zoala's home page signed in.
Checklist
- Verify the ID token (your library does): issuer
https://www.eduspazeconnect.com, audience your client ID, RS256 keys from the JWKS. - Match by
preferred_username; never create accounts from a claim you didn't expect. - Keep the client secret on the server. Make a new one in the portal if it ever leaks — the old one stops working at once.
