NAME

WWW::Zitadel::OIDC - OIDC client for Zitadel - token verification, JWKS, discovery

VERSION

version 0.001

SYNOPSIS

use WWW::Zitadel::OIDC;

my $oidc = WWW::Zitadel::OIDC->new(
    issuer => 'https://zitadel.example.com',
);

# Discovery
my $config = $oidc->discovery;

# Fetch JWKS
my $jwks = $oidc->jwks;

# Verify an access token (JWT)
my $claims = $oidc->verify_token($access_token);

# Verify with audience check
my $claims = $oidc->verify_token($token,
    audience => 'my-client-id',
);

# Fetch user info
my $user = $oidc->userinfo($access_token);

# Token introspection (requires client credentials)
my $info = $oidc->introspect($token,
    client_id     => $client_id,
    client_secret => $client_secret,
);

# Token endpoint helpers
my $cc = $oidc->client_credentials_token(
    client_id     => $client_id,
    client_secret => $client_secret,
    scope         => 'openid profile',
);

my $refreshed = $oidc->refresh_token(
    $refresh_token,
    client_id     => $client_id,
    client_secret => $client_secret,
);

DESCRIPTION

OIDC client for Zitadel. Handles discovery, JWKS fetching, JWT verification via Crypt::JWT, and userinfo/introspection endpoints.

Token verification automatically retries with a refreshed JWKS on failure, handling key rotation transparently.

issuer

Required. The Zitadel issuer URL, e.g. https://zitadel.example.com.

ua

Optional LWP::UserAgent instance. A default one with 10s timeout is created.

discovery

Returns the parsed OpenID Connect discovery document from /.well-known/openid-configuration.

jwks

Returns the JSON Web Key Set. Caches after first fetch. Pass force_refresh => 1 to bypass the cache.

verify_token

my $claims = $oidc->verify_token($jwt, %options);

Verifies a JWT access token against the JWKS. Returns the decoded claims hashref on success, dies on failure.

Options: audience, verify_exp (default 1), verify_iat (default 0), verify_nbf (default 0), accepted_key_alg (default RS256/384/512).

userinfo

my $info = $oidc->userinfo($access_token);

Calls the UserInfo endpoint with the given access token. Returns parsed JSON response.

introspect

my $info = $oidc->introspect($token,
    client_id     => $id,
    client_secret => $secret,
);

Calls the token introspection endpoint. Requires client_id and client_secret for authentication.

token

my $token_response = $oidc->token(
    grant_type => 'client_credentials',
    client_id => $id,
    client_secret => $secret,
    scope => 'openid profile',
);

Generic token endpoint helper. Sends a form-encoded POST to the discovered token_endpoint and returns parsed JSON.

client_credentials_token

my $token_response = $oidc->client_credentials_token(
    client_id => $id,
    client_secret => $secret,
    scope => 'openid profile',
);

Convenience wrapper around token for client_credentials.

refresh_token

my $token_response = $oidc->refresh_token(
    $refresh_token,
    client_id => $id,
    client_secret => $secret,
);

Convenience wrapper around token for refresh_token.

exchange_authorization_code

my $token_response = $oidc->exchange_authorization_code(
    code => $code,
    redirect_uri => $redirect_uri,
    client_id => $id,
    client_secret => $secret,
    code_verifier => $verifier,
);

Convenience wrapper around token for authorization_code.

SEE ALSO

WWW::Zitadel, Crypt::JWT

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-www-zitadel/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.