NAME

Punk::OAuth2::Presets - provider presets for Punk::OAuth2

SYNOPSIS

package MyApp;
use Punk;
use Punk::Plugin::OAuth2;

plugin 'OAuth2';

# a preset supplies the endpoints; you supply the credentials
oauth2 google => {
	preset        => 'google',
	client_id     => secret('oauth.google_id'),
	client_secret => secret('oauth.google_secret'),
};

# any preset field can be replaced alongside it
oauth2 github => {
	preset        => 'github',
	scope         => 'read:user user:email repo',
	client_id     => secret('oauth.github_id'),
	client_secret => secret('oauth.github_secret'),
};

# the config a preset expands to, if you want to see it
my $cfg = Punk::OAuth2::Presets::preset('google');

DESCRIPTION

A preset is a named bundle of provider configuration: the endpoints, default scope and client-authentication style for a provider whose details are fixed and public, so that declaring it takes a client id and secret rather than six URLs copied from someone's documentation.

Presets are built in C (include/pox/pox_presets.h) and handed to the provider constructor, which merges them under your own configuration. Nothing here is required: a provider declared without preset works exactly the same way, you just write the endpoints out yourself.

FUNCTIONS

preset

my $cfg = Punk::OAuth2::Presets::preset($name);

Returns a fresh hashref of configuration for $name, which is google, github or oidc. Not exported, and rarely called directly - the usual route is preset => $name in a provider declaration, which calls this for you. The hashref is newly built on every call, so modifying it cannot affect any other provider.

Croaks on an unknown name.

PRESETS

google

OpenID Connect against Google, with the endpoints hard-coded rather than discovered, so a login costs no discovery round trip:

oidc                    1
issuer                  https://accounts.google.com
authorization_endpoint  https://accounts.google.com/o/oauth2/v2/auth
token_endpoint          https://oauth2.googleapis.com/token
jwks_uri                https://www.googleapis.com/oauth2/v3/certs
userinfo_endpoint       https://openidconnect.googleapis.com/v1/userinfo
scope                   openid email profile
auth_method             body

Identity comes from the verified id_token, as for any OIDC provider.

github

GitHub is not an OpenID Connect provider: there is no id_token and no jwks_uri, so identity is fetched from the user API with the access token instead.

oidc                    0
authorization_endpoint  https://github.com/login/oauth/authorize
token_endpoint          https://github.com/login/oauth/access_token
identity_endpoint       https://api.github.com/user
emails_endpoint         https://api.github.com/user/emails
scope                   read:user user:email
auth_method             body
token_headers           { Accept => 'application/json' }
identity_map            \&Punk::OAuth2::_github_identity

token_headers is not decoration: GitHub's token endpoint answers in application/x-www-form-urlencoded unless asked for JSON.

The separate emails_endpoint exists because GET /user omits the email address whenever the account keeps it private, which is the default. See "IDENTITY MAPPING" for how the two responses are combined.

oidc

The generic case - no endpoints at all, just the two switches that tell the provider to find them itself:

oidc                    1
discovery               1

Set issuer alongside it and everything else is read from that issuer's RFC 8414 / OpenID Connect discovery document. This is the preset to reach for with any standards-compliant identity provider that is not Google.

oauth2 corp => {
	preset        => 'oidc',
	issuer        => 'https://idp.corp.example',
	client_id     => '...',
	client_secret => '...',
};

OVERRIDING

The provider constructor lays the preset down first and then your configuration on top, key by key, with the preset key itself dropped. So any field above can simply be named again in the declaration to replace it:

oauth2 github => {
	preset      => 'github',
	scope       => 'read:user user:email repo',   # replaces the default
	client_id   => '...',
};

The merge is flat, not deep. Giving your own token_headers replaces the preset's hashref outright rather than adding to it, so carry over any part of it you still want:

token_headers => { Accept => 'application/json', 'X-Trace' => $id },

Fields no preset sets are filled in afterwards by the provider itself: auth_method defaults to basic, algs to RS256 and ES256, leeway to 60 seconds, scope to empty and discovery to off. That is why the two presets that want auth_method set it explicitly.

IDENTITY MAPPING

A plain OAuth2 provider - one with identity_endpoint rather than oidc - returns whatever shape its user API happens to use, so the provider needs a way to turn that into the normalized identity the rest of Punk::OAuth2 expects. That is identity_map: a coderef called with the decoded identity response and the decoded emails response (undef when there is no emails_endpoint, or it did not answer 200), returning a hashref that is merged into the identity.

identity_map => sub {
	my ($user, $emails) = @_;
	return { sub => $user->{uid}, email => $user->{mail} };
},

The github preset points this at Punk::OAuth2::_github_identity, an XSUB that produces:

sub

$user->{id}, stringified. GitHub sends it as a number, and an identity that changes type between JSON decoders is a subtle way to lose a session.

email

The primary address from the emails response, or the first one it lists if none is flagged primary, falling back to $user->{email} when the emails endpoint gave nothing.

email_verified

The verified flag belonging to whichever address was chosen, or undef if the response did not say.

name

$user->{name}, falling back to $user->{login} - the display name is optional on GitHub and frequently unset.

picture

$user->{avatar_url}.

With no identity_map, the provider falls back to reading sub (or id), email and name straight off the identity response. Either way the untouched payload is always available as raw, so a mapping that drops a field costs you nothing.

SEE ALSO

Punk::Plugin::OAuth2 for the oauth2 declaration these presets are used from, and Punk::OAuth2::Provider for endpoint resolution, discovery and the full set of provider fields.

AUTHOR

LNATION, <email at lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION <email@lnation.org>.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)