INTEGRATION GUIDELINES
Integration protocols and specifications for Savelo Identity Provider (IdP) authentication.
Overview & Architecture
Savelo IdP eliminates passwords entirely using a cryptographic dual-channel mechanism:
Users login via 6-digit CSPRNG numeric OTP (salted with HMAC-SHA256) or Magic Links.
Confirming a login on a secondary mobile device triggers instant push to the initiating desktop via Redis SSE.
Strict RFC 7636 PKCE code challenges mitigate authorization code interception attacks.
Client Registration
Before your service can authenticate users, provision your application in the Developer Console:
- Open the Developer Console and click "Register Application".
- Enter your service name (e.g.
Saveroute API) and whitelisted callback URLs. - Copy your Client ID and Client Secret. The secret is hashed with SHA-256 and will never be shown again.
- Store credentials in your service environment variables.
PKCE Authorization Flow
When a user initiates authentication, redirect them to the authorization endpoint:
curl -X GET "http://localhost:3000/oauth/authorize?\ client_id=savelo-tools&\ redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fapi%2Fauth%2Fcallback&\ response_type=code&\ state=xyz123&\ code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&\ code_challenge_method=S256"
Token Exchange & Rotation
Upon completing verification, Savelo IdP redirects back to your callback URL with an authorization_code. Exchange this code for tokens at POST /api/oauth/token:
// Next.js App Router: app/api/auth/callback/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
const code = req.nextUrl.searchParams.get("code");
const state = req.nextUrl.searchParams.get("state");
const verifier = req.cookies.get("pkce_verifier")?.value;
if (!code || !verifier) {
return NextResponse.json({ error: "Missing authorization code or verifier" }, { status: 400 });
}
const tokenRes = await fetch("http://localhost:3000/api/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
client_id: process.env.SAVELO_CLIENT_ID!,
client_secret: process.env.SAVELO_CLIENT_SECRET!,
code,
redirect_uri: process.env.SAVELO_REDIRECT_URI!,
code_verifier: verifier,
}),
});
const tokens = await tokenRes.json();
// tokens: { access_token, id_token, refresh_token, token_type: "Bearer", expires_in: 900 }
return NextResponse.redirect(new URL("/dashboard", req.url));
}Standard Endpoints
/api/.well-known/openid-configuration/api/.well-known/jwks.json/api/oauth/token/api/oauth/userinfo/api/oauth/revoke