The idea
When a launcher loads a learning app, it appends a query parameter to the URL: ?edu_session=<JWT>. That JWT is signed by the launcher's issuer, names the child, and is valid for five minutes. The app verifies the token against the issuer's public JWKS, reads the email out of it, drops its own session cookie, and redirects to strip the parameter.
That's the entire protocol. No client_id, no callback URLs, no refresh tokens, no PKCE, no OIDC discovery dance.
The flow
┌──────────┐ 1. mint(child, aud) ┌───────────────┐
│ Launcher │ ─────────────────────► │ Issuer │
│ │ ◄───────────────────── │ (signs JWT) │
└────┬─────┘ 2. edu_session JWT └───────────────┘
│
│ 3. GET https://your-app.com/?edu_session=<jwt>
▼
┌────────────┐ 4. verify(jwt, JWKS) ┌──────────────┐
│ Your app │ ──────────────────────► │ Public JWKS │
│ │ └──────────────┘
│ │ 5. setSessionCookie(email)
│ │ 6. 302 → same path without ?edu_session
└────────────┘
The integration, in full
Server-side, Node + jose:
import { createRemoteJWKSet, jwtVerify } from "jose";
const jwks = createRemoteJWKSet(
new URL("https://issuer.example-launcher.com/.well-known/jwks.json")
);
export async function eduSSO(req, res, next) {
const token = req.query.edu_session;
if (!token) return next();
try {
const { payload } = await jwtVerify(token, jwks, {
issuer: "https://issuer.example-launcher.com",
audience: "your-app-id",
clockTolerance: 5,
});
await upsertUser({ email: payload.email, name: payload.name });
await setSessionCookie(res, payload.email);
const clean = new URL(req.url, `https://${req.headers.host}`);
clean.searchParams.delete("edu_session");
return res.redirect(302, clean.pathname + clean.search);
} catch {
return next();
}
}
Mount it as middleware at the root of your app. That's the whole integration.
The token
{
"iss": "https://issuer.example-launcher.com",
"aud": "your-app-id",
"sub": "child:abc123",
"email": "student@example.com",
"email_verified": true,
"name": "Sam",
"iat": 1779150000,
"exp": 1779150300,
"jti": "01HX5XYV6FPK3R3D6T2H8E2VPR"
}
none.
Read the spec
- Overview & FAQ specs/edu-sso/protocol.md
- Issuer implementation spec specs/edu-sso/issuer.md
- Relying-party implementation spec specs/edu-sso/tutor.md
- Conformance checklist specs/edu-sso/conformance.md
- Reference implementations specs/edu-sso/examples/ — school-issuer, example-tutor, school-host
