NAME

WWW::Authentik - Perl client for the authentik identity provider (OIDC + REST API v3)

VERSION

version 0.001

SYNOPSIS

use WWW::Authentik;

my $ak = WWW::Authentik->new(
  base_url    => 'https://id.example.org',
  application => 'my-app',                   # the application slug, for OIDC
  client_id   => $client_id,                 # its provider's client id, checked as the audience
  token       => $ENV{AUTHENTIK_TOKEN},      # an API token, for the REST API
);

# OpenID Connect against the application
my $claims = $ak->oidc->verify_token( $jwt, type => 'access' );

# REST API v3, repeatable
$ak->api->ensure_user( username => 'alice', name => 'Alice', password => $pw );
my $r = $ak->api->ensure_application( slug => 'my-app', name => 'My App', provider_name => 'my-app' );
print $r->{changed};   # 'created', 'updated' or ''

# another application, same instance and token
my $other = $ak->for_application('second-app');

DESCRIPTION

A client for authentik in two parts: WWW::Authentik::OIDC for what an application does with its OpenID Connect endpoints, and WWW::Authentik::API for bringing an authentik into a wanted state from Perl, repeatably.

authentik has no realm. The API is instance-wide under <base_url>/api/v3/ and needs an API token; OpenID Connect is addressed per application, with discovery, keys and the end-session endpoint under <base_url>/application/o/<slug>/ and the token, userinfo, introspection, revocation and device endpoints shared by the whole instance. So "token" and "application" are both optional: without a slug there is no "oidc", without a token there is no "api", and either may be left out.

An authentik API token is long-lived and is used as it is. There is no login to manage and nothing to renew; authentik answers a token it does not accept with 403, not 401.

Coming from WWW::Keycloak

The two distributions have the same shape, but two return values differ, and deliberately. create_* and update_* return the representation, not an id, because authentik answers a create with the whole object and sends no Location header. And ensure_* returns { object => \%rep, changed => ... }, not { id => ..., changed => ... }, because authentik has no single kind of identifier: an application is addressed by its slug, a provider by an integer, a group by a UUID, a token by its identifier. The caller almost always needs the next key out of the object anyway.

Developed and tested against authentik 2026.8.3.

base_url

Required. Where authentik is, without /api/v3 and without /application/o/. Trailing slashes are removed.

application

The slug of the application "oidc" talks to. Without it "oidc" throws a validation error.

token

An authentik API token, sent as a bearer token with every call of "api". Without it "api" throws a validation error. It is used as it is and never renewed.

client_id

The client id of "application"'s provider. "verify_token" in WWW::Authentik::OIDC checks it as the audience, which is what keeps a token of another application of the same authentik from passing. Worth setting.

ua

The LWP::UserAgent every part shares. "default_ua" builds it.

default_ua

my $ua = WWW::Authentik->default_ua;

The user agent this client wants, for a caller who needs to build their own and keep the two settings that matter:

max_redirect => 0

authentik redirects at the authorize endpoint and between the stages of a flow. Those answers are read, not followed, and no redirect may carry the API token anywhere.

send_te => 0

An injected user agent without this will hang. LWP announces TE: deflate,gzip;q=0.3 and Connection: TE, close by default, and authentik 2026.8.3 answers every second request carrying the TE connection token not at all: the call sits until the timeout, the next one is fine, the one after that hangs again. Observed against 2026.8.3 with plain sockets as well, so it is authentik's front end, not LWP. send_te => 0 tells Net::HTTP to leave the header out, and libwww-perl has taken the option since 6.33. On anything older this method throws rather than hand back a user agent that works every other time.

oidc

The WWW::Authentik::OIDC of "application".

api

The WWW::Authentik::API of this instance.

api_url

print $ak->api_url;   # https://id.example.org/api/v3

application_url

print $ak->application_url;   # https://id.example.org/application/o/my-app

Where this application's OpenID Connect endpoints live, without the trailing slash. The slug is URI encoded.

issuer

print $ak->issuer;   # https://id.example.org/application/o/my-app/

The issuer in its address form, which is what authentik puts into a token while the provider is set to issuer_mode: per_provider (its default). The authoritative value is "issuer" in WWW::Authentik::OIDC, read out of the discovery document; with issuer_mode: global the two differ.

for_application

my $other = $ak->for_application('second-app');

The same client for another application, sharing the user agent and the API token.

SUPPORT

Issues

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

IRC

Join #kubernetes on irc.perl.org or message Getty directly.

CONTRIBUTING

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

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

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