Identity Platform / Firebase Auth
floci-gcp emulates the Google Identity Toolkit API (identitytoolkit.googleapis.com v1)
wire-compatibly with the official Firebase Auth emulator: same paths, same unsigned
JWTs, same error strings. Anything that works against firebase emulators:start --only auth
is the compatibility target.
Configuration
| Variable | Default | Description |
|---|---|---|
FLOCI_GCP_SERVICES_FIREBASEAUTH_ENABLED |
true |
Enable/disable Firebase Auth |
Endpoint
Set FIREBASE_AUTH_EMULATOR_HOST=localhost:4588. Firebase SDKs then prefix requests with
the API hostname as a path, which floci-gcp serves directly on its single port:
| Method | Path |
|---|---|
POST |
/identitytoolkit.googleapis.com/v1/accounts:signUp | :signInWithPassword | :signInWithCustomToken | :lookup | :update | :delete (client, ?key= any non-empty API key) |
POST |
/identitytoolkit.googleapis.com/v1/projects/{project}/accounts[:lookup\|:update\|:delete\|:batchDelete] (admin, Authorization: Bearer owner) |
GET |
/identitytoolkit.googleapis.com/v1/projects/{project}/accounts:batchGet (admin listUsers) |
POST |
/securetoken.googleapis.com/v1/token (refresh; JSON or form-urlencoded) |
DELETE |
/emulator/v1/projects/{project}/accounts (test helper: delete all users) |
Tokens
- ID tokens are unsigned JWTs (
alg: none, empty signature) with the claims the Admin SDK's emulator-mode verifier checks:iss=https://securetoken.google.com/{project},aud={project},sub/user_id,auth_time,firebase.{identities, sign_in_provider}. Custom claims (fromsetCustomUserClaimsor custom-tokenclaims) are merged into the payload. - Refresh tokens follow the emulator's base64-JSON record format;
POST /securetoken.../tokenwithgrant_type=refresh_tokenre-issues tokens. - Token revocation:
revokeRefreshTokenssetsvalidSince; tokens withiat < validSincefail withTOKEN_EXPIRED(wall-clockexpis intentionally not enforced, like the emulator). - Custom tokens: Admin SDK JWTs (signed or unsigned) and the emulator's strict-JSON form
(
{"uid": "...", "claims": {...}}) are both accepted.
Quick Start
// export FIREBASE_AUTH_EMULATOR_HOST=localhost:4588
FirebaseApp app = FirebaseApp.initializeApp(FirebaseOptions.builder()
.setProjectId("floci-local") // the emulator's default project
.setCredentials(new EmulatorCredentials())
.build());
FirebaseAuth auth = FirebaseAuth.getInstance(app);
auth.createUser(new UserRecord.CreateRequest()
.setUid("alice").setEmail("alice@example.com").setPassword("secret123"));
auth.setCustomUserClaims("alice", Map.of("role", "admin"));
String customToken = auth.createCustomToken("alice");
// client exchanges it at accounts:signInWithCustomToken, then:
FirebaseToken decoded = auth.verifyIdToken(idToken);
# client sign-up (any non-empty API key)
curl -X POST 'http://localhost:4588/identitytoolkit.googleapis.com/v1/accounts:signUp?key=fake-api-key' \
-H 'Content-Type: application/json' \
-d '{"email":"alice@example.com","password":"secret123"}'
# refresh
curl -X POST 'http://localhost:4588/securetoken.googleapis.com/v1/token?key=fake-api-key' \
-d 'grant_type=refresh_token&refresh_token=<refreshToken>'
Scope and deviations
- Client API-key calls resolve to the emulator's default project
(
floci-gcp.default-project-id), mirroring the official emulator's single-project model. - Phase 1 covers email/password, anonymous, and custom-token flows plus the admin user CRUD
surface (create/lookup/update/delete/batchGet/batchDelete). Not yet implemented: OOB codes
(email verification / password reset), email-link, IdP, phone, MFA, passkeys, tenants,
session cookies, and the legacy v3
relyingpartypaths — these return 404 (the official emulator returns 501 for unimplemented operations). - Passwords are stored in the emulator's literal
fakeHash:salt=...:password=...format — a dev fixture, not a security boundary, identical to the official emulator. securetokenresponses reportproject_id: "12345", the emulator's hardcoded project number.