Install
$ agentstack add skill-kennguyen887-agent-foundation-integrate-identity-providers ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Integrate identity providers
Adding external login (Google/Apple/Facebook) and identity verification / KYC (e.g. Singpass) to a backend, the right way: as an OIDC relying party that delegates auth to the provider and verifies the result cryptographically. Examples name real public providers; the flow is a standard so it ports to any language. principle → ▸ Example → ▸ Other stacks. The frontend login UI + session (NextAuth, route guards) is secure-a-frontend-app; exposing your own API to partners is integrate-external-services §5. This skill is the backend/server + verification side.
Core principle
Never roll your own identity or trust a client-supplied identity blob. Delegate authentication to an OIDC provider, verify the returned token's signature + claims yourself, then map the external identity to your own user. For a KYC provider (Singpass), the returned attributes are authoritative — store them as verified, don't let the user edit them.
1. The relying-party flow (authorization code + PKCE)
- Redirect the user to the provider's
authorizeendpoint withstate(CSRF) +nonce(replay) +
PKCE code_challenge; keep state/code_verifier server-side (or in a signed cookie). On the callback, check state, then exchange the code at the token endpoint for an id_token + access_token. Confidential clients authenticate the exchange with a client secret or a signed client_assertion JWT (private-key JWT) — never expose the secret to the browser. `` GET /authorize?response_type=code&client_id=…&redirect_uri=…&scope=openid profile&state=…&nonce=…&code_challenge=…&code_challenge_method=S256 → callback ?code=…&state=… → POST /token { code, code_verifier, client_assertion } → { id_token, access_token } ``
- Then fetch verified attributes (the
userinfoendpoint, or a provider-specific person API) using
the access token. The user never hands you their identity — the provider asserts it. ▸ Other stacks: any OIDC/OAuth2 client lib (AppAuth, MSAL, passport-openidconnect, golang.org/x/oauth2). Principle: authorization-code + PKCE, validate state, exchange server-side, fetch attributes — never implicit/client-asserted identity.
2. Validate the token (what every service does)
- Discover, then verify. Fetch the provider's
/.well-known/openid-configurationonce (cache it)
to get jwks_uri + endpoints; verify the id_token/JWT signature against the JWKS and check iss, aud, exp, and nonce. For opaque access tokens, introspect at the provider instead. Cache the JWKS (refresh on unknown kid); never skip signature verification. ``ts const { jwks_uri, issuer } = await discover(idpBaseUrl); // .well-known, cached const claims = await verifyJwt(idToken, { jwks: jwks_uri, issuer, audience: clientId }); // sig + iss + aud + exp ` ▸ *Other stacks:* the same — discovery doc → JWKS → verify signature + standard claims, or token introspection for opaque tokens. (You already saw the validate side in integrate-external-services` §5.)
3. Centralize many IdPs behind one broker
- Don't make every service implement Google + Apple + Singpass. Front them with **one identity
broker (e.g. Keycloak) that brokers each upstream IdP and issues your own uniform token**; your services then validate just that one issuer (§2). Adding an IdP becomes a broker config change, not a fleet-wide code change. ▸ Other stacks: Auth0/Cognito/Okta/Keycloak as an identity broker; an internal auth service that normalizes providers. Principle: one issuer your services trust, many upstream IdPs behind it.
4. Map an external identity to your user
- Link by a stable
(provider, subject)pair, not by email alone — emails change and can be reused;
the provider's sub is stable. Store which IdP verified the user; on first login, provision the user (and link additional providers to the same account deliberately). ``ts const identity = { provider: 'singpass', sub: claims.sub }; // stable key let user = await users.findByIdentity(identity) ?? await users.provisionFrom(identity, claims); ` ▸ *Other stacks:* an identities table keyed by (provider, subject)` linked to one user. Principle: stable subject is the key; email is a (mutable) attribute.
5. Identity verification (KYC) vs login
- A national digital identity (Singpass) returns verified attributes (legal name, national id,
DOB). Treat them as authoritative: store a verified flag + the source + a timestamp, don't let the user edit verified fields, and re-verify on the schedule your compliance requires. This is stronger than social login (which only proves "controls this Google account"). Distinguish the two in your model — a "logged in via Google" user is not "identity-verified". ▸ Other stacks: any eID / KYC provider returns asserted attributes; record provenance + verified-at, gate sensitive actions on verification level.
Security checklist
state+nonce+ PKCE on every flow; reject a callback whosestatedoesn't match.- Verify signature +
iss/aud/expon every token; cache JWKS; introspect opaque tokens. - Confidential-client secret/private key in a vault, never in the client or the repo.
- Never log tokens or PII (id numbers) — mask (see
write-service-code§7). Short-lived access
tokens + refresh handling; store only what you need.
Vendor recipes (step-by-step)
Step-by-step guides for specific providers live in [references/](./references/) and load on demand.
- [
references/keycloak.md](./references/keycloak.md) — Keycloak as token authority + identity broker: discovery, JWKS verify, client-credentials (latency-safe TTL), brokering Google/Apple/Singpass. - [
references/singpass.md](./references/singpass.md) — Singpass (NDI OIDC) relying-party: private-key-JWT client assertion, JWE-encrypted ID token (decrypt → verify), hosted JWKS, verified Myinfo (KYC) attributes. - (more per provider — social login, …)
Verification
- Login uses authorization-code + PKCE, validates
state, exchanges server-side — no implicit flow. - Every token is signature-verified against JWKS with
iss/aud/exp(or introspected); JWKS cached. - Many IdPs sit behind one broker/issuer your services validate.
- Users are linked by
(provider, subject), not email; the verifying IdP is recorded. - KYC attributes are stored verified + provenance + timestamp, not user-editable; verification level
is distinct from "logged in".
Related
secure-a-frontend-app— the frontend login UI, NextAuth, session, route guards (the client side of this).integrate-external-services§5 (token introspection / partner edge), §2 (resilient HTTP to the IdP).write-cross-cutting-code(the guard that reads the verified identity) ·design-an-error-model·
write-service-code §7 (mask PII).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: kennguyen887
- Source: kennguyen887/agent-foundation
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.