huudis.oidc.consent_granted.v1
Fires the first time a user consents to an OIDC client — either by clicking "Allow" on a third-party client's consent screen, or implicitly on first sign-in to a first-party client.
Subscribe if you want a clean "this user has now agreed to sign into my app" trigger — useful for kicking off in-product onboarding from the consumer side rather than the workspace-creation side.
Not yet emitted in v1. Audit log carries
oidc_consent_granted.
When it fires
When a new OidcConsent row is created:
- A third-party OIDC client's authorize flow reaches the consent screen, the user clicks "Allow", and they're redirected back with a code.
- A first-party client's authorize flow completes for the first time (no visible consent screen for first-party).
Subsequent sign-ins to the same client do not re-fire the event — consent persists until the user revokes. If the user revokes and signs in again, a fresh consent row is created and the event fires again.
Payload
{
"id": "evt_01KPG…",
"type": "huudis.oidc.consent_granted.v1",
"createdAt": "2026-05-12T11:02:00.000Z",
"data": {
"consentId": "ocs_01KPG…",
"userId": "usr_01KPG…",
"userEmail": "ibu.rina@cafe-sumur.id",
"clientId": "oc_meja_studio",
"clientName": "MejaStudio",
"clientAccountId": "acc_01KPG30…",
"scopes": ["openid", "profile", "email"],
"isFirstParty": false,
"consentedAt": "2026-05-12T11:02:00.000Z"
}
}
clientAccountId is the workspace that owns the OIDC client (the one whose admin registered it) — not the user's own workspace. Useful for routing the event to that workspace's downstream systems.
Handler examples
// Node — your product is MejaStudio; this is the first-touch
if (event.type === 'huudis.oidc.consent_granted.v1' && event.data.clientId === MY_CLIENT_ID) {
const c = event.data;
await db.users.upsert({
huudisId: c.userId,
email: c.userEmail,
consentedAt: c.consentedAt,
});
await onboarding.start(c.userId);
}
# Python
if event["type"] == "huudis.oidc.consent_granted.v1":
c = event["data"]
if c["clientId"] == MY_CLIENT_ID:
db.users.upsert(huudis_id=c["userId"], email=c["userEmail"])
onboarding.start(c["userId"])
What to do
- Upsert the user in your own user table keyed by
userId. This is the cleanest "new user of my product" trigger. - Trigger product-side onboarding (welcome email, tutorial unlock).
- Tag your analytics with
clientAccountIdif you want to attribute users to the workspace that owns the client they signed into.
Avoid:
- Treating consent as authentication. The user has agreed to let your app see their identity, but the session is independent; check the access token, not the consent.
- Granting workspace permissions. Consent is per-client, not per-workspace. The user is using your client, not joining your workspace.
Common pitfalls
- Consent vs. session. A user can consent and then never actually use the app. If you need "first active use" you want a product-specific event, not consent-granted.
- Re-consent on scope expansion. If your client later adds a new scope to the request, the user is re-prompted on next sign-in — a fresh consent row is created and this event fires again with the new scope list.
- First-party clients fire too. Filter by
isFirstParty: falseif you're only interested in third-party flows.
Related events
huudis.user.created.v1— new user; precedes consent for fresh sign-ups.huudis.session.created.v1— the session that the consent enabled.
Next
- Consents resource — per-user consent management.
- OIDC clients — the clients consents apply to.