Catalyst-Plugin-OpenIDConnect
view release on metacpan or search on metacpan
IMPLEMENTATION_GUIDE.md view on Meta::CPAN
The standard, most secure flow for web applications:
```
1. Client redirects user to /openidconnect/authorize with:
- response_type=code
- client_id
- redirect_uri
- scope
- state (CSRF protection)
- nonce (optional, binds to session)
- code_challenge (required for public clients; recommended for all â see PKCE below)
- code_challenge_method=S256 (required when code_challenge is supplied)
2. User authenticates (handled by application)
3. Server issues authorization code via redirect
4. Client exchanges code for tokens at /openidconnect/token with:
- grant_type=authorization_code
- code
- redirect_uri
- client_id
- client_secret (omit for public clients)
- code_verifier (required when code_challenge was sent in step 1)
5. Server verifies and issues:
- id_token (JWT with user claims)
- access_token (JWT for API access)
- refresh_token (JWT for token refresh)
- expires_in
```
### Token Types
#### ID Token
- Contains user identity claims (name, email, etc.)
- Signed JWT (RS256)
- Expires in 1 hour
- Includes nonce (if provided) for CSRF protection
#### Access Token
- Authorization token for API access
- Signed JWT
- Expires in 1 hour
- Contains scope information
#### Refresh Token
- Long-lived token for refreshing access tokens
- Signed JWT
- Expires in 30 days
- Not accessible to browser (HTTP-only cookies in production)
## Configuration
### Issuer Configuration
```perl
<Plugin::OpenIDConnect>
<issuer>
url = http://localhost:5000
private_key_file = /path/to/private.pem
public_key_file = /path/to/public.pem
key_id = my-key-123
</issuer>
```
**Fields:**
- `url` - The issuer identifier (in iss claim)
- `private_key_file` - Path to RSA private key (PEM format)
- `public_key_file` - Path to RSA public key (optional, derived from private)
- `key_id` - Key identifier for JWK Set
### Client Configuration
```perl
<clients>
<my-client>
client_secret = secret123
redirect_uris = http://app.example.com/callback
post_logout_redirect_uris = http://app.example.com/logged-out
response_types = code
grant_types = authorization_code refresh_token
scope = openid profile email
</my-client>
</clients>
```
**Fields:**
- `client_secret` - Shared secret for token endpoint
- `redirect_uris` - Arrayref or whitespace-separated string of URIs the client is permitted to redirect to after authorization
- `post_logout_redirect_uris` - Arrayref or whitespace-separated string of URIs the client is permitted to redirect to after logout. Required when the client uses `post_logout_redirect_uri` at the logout endpoint.
- `response_types` - Supported response types (e.g., "code")
- `grant_types` - Supported grant types (e.g., "authorization_code")
- `scope` - Default/allowed scopes
> Both `redirect_uris` and `post_logout_redirect_uris` accept the same formats:
> an arrayref in YAML/JSON/Perl-hash config, or a whitespace-separated string
> in Apache-style (`Config::General`) config. Both are matched by exact string
> comparison â prefix matching and host-only matching are not permitted.
### User Claims Mapping
Map user object attributes to OpenID Connect claims:
```perl
<user_claims>
sub = id
name = full_name
email = email_address
picture = avatar_url
email_verified = is_email_verified
</user_claims>
```
The format is: `<oidc_claim> = <user_attribute_path>`
Nested attributes use dot notation: `claims = user.profile.claims`
## Standard OpenID Connect Claims
The plugin supports the following standard claims:
**Profile Claims:**
- `sub` - Subject (unique user identifier)
- `name` - Full name
- `given_name` - Given (first) name
- `family_name` - Family (last) name
- `middle_name` - Middle name
- `nickname` - Nickname
( run in 1.616 second using v1.01-cache-2.11-cpan-13bb782fe5a )