Reference Yeti auth-provider plugin: a typed OidcProvider
implementation for Okta. Owns Okta token validation end-to-end —
the platform routes any request whose token's iss claim matches
our configured Okta org straight to this component.
resources/provider.rsdeclaresimpl OidcProvider for OktaProvider.- The yeti-compiler auto-detects that impl and switches the wasm
component's WIT world from
customer-apptoauth-provider-export(yeti:ingress/auth-provider-export). - A
Guestimpl for theyeti:ingress/auth-providerinterface is emitted automatically — it delegates every WIT verb (validate-token,lookup-user,exchange-code,refresh-token,revoke-token,discover,describe) to our impl. - On load, the host calls
describe()and registers us under the issuer claims we return. Tokens flow to us byissmatch.
No register_hook calls. No Plugin::register_hooks. The WIT
export is the registration.
| Verb | Standard | Behavior |
|---|---|---|
discover |
OIDC Discovery 1.0 | GET {domain}/.well-known/openid-configuration |
validate_token |
RFC 7662 (introspection) | POST {domain}/oauth2/v1/introspect, check active + aud, return AuthIdentity |
lookup_user |
OIDC Core §5.3 + Okta Mgmt API | GET {domain}/api/v1/users/{sub}, run role-mapping on groups[0], return UserInfo with roles |
exchange_code |
RFC 6749 §4.1.3 | POST {domain}/oauth2/v1/token with authorization_code grant |
refresh_token |
RFC 6749 §6 | POST {domain}/oauth2/v1/token with refresh_token grant |
revoke_token |
RFC 7009 | POST {domain}/oauth2/v1/revoke |
describe |
(yeti routing metadata) | Returns { name: "okta", issuers: [<domain>], audiences: [<aud>] } |
Same shape as the pre-WASM v0.1 OAuth-callback hook, but moved
inside lookup_user where the WIT UserInfo.roles field lives.
Configure via okta_config() and role_map() in
resources/provider.rs.
The default config maps:
Okta group → Yeti role
─────────────────────────
Admins → admin
Engineers → developer
Viewers → viewer
Anything not in the map passes through unchanged (the raw group name becomes the role).
For now, edit the constants in okta_config() and role_map() at
the top of resources/provider.rs:
domain— Okta org base URL (no trailing slash)client_id/client_secret— OAuth2 client credentialsaudience— expectedaudclaimrole_claim_path— JSON path into the userinfo response
The [package.metadata.okta] block in Cargo.toml mirrors these
values for forward-compat. When the SDK adds a runtime app-metadata
accessor, this provider will read them at startup — until then, keep
the two in sync by hand.
Why not
[package.metadata.auth.okta]? Because the host parses any[package.metadata.auth.*]block as auth-CONSUMER config (auth methods, providers, role table). An auth-PROVIDER plugin exposes verbs for other apps to consume; it doesn't consume auth itself. Keeping our config underoktaavoids tripping the consumer path.
The pre-WASM TokenClaimsExtender shape (lifting raw provider
claims into the JWT under extra.okta.*) is not implemented in
v0.2. The WIT auth-identity record exposes only
{ principal, username, issued_via, claims: bytes } — the claims
bag is opaque bytes via WIT, and the SDK AuthIdentity doesn't
surface it. To restore the JWT-extras behavior, either:
- Encode the JSON profile into
AuthIdentity.claims: byteson the WIT side, OR - Add a
claims: serde_json::Valuefield toyeti_sdk::oidc::AuthIdentityand plumb it through the compiler'ssdk_auth_identity_to_witconverter.
Either is a follow-up; v0.2 keeps the surface minimal.
v0.1 used register_hook("yeti.auth.oauth.v1", ..) and
register_hook("yeti.auth.token.v1", ..). Those calls were silently
inert in the wasm-component world — Plugin::register_hooks is
never invoked for wasm components.
If you forked v0.1 for your own IDP, the migration shape is:
- Drop
impl Plugin for ...and theregister_hooksbody. - Add
#[derive(Default)] pub struct YourProvider; impl OidcProvider for YourProvider— fill in the verbs your provider supports. The defaults returnErr("not implemented").- The compiler picks up the impl automatically. Nothing else to do.