feat(oidc): add Authentik OpenID Connect Provider#199
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds an Authentik OpenID provider and a guide covering registration, configuration, sign-in initiation, and session retrieval. ChangesAuthentik OAuth integration
Sequence Diagram(s)sequenceDiagram
participant Browser
participant createAuthClient
participant apiSignIn as api.signIn
participant Authentik
alt direct navigation
Browser->>apiSignIn: visit sign-in route
else client-side sign-in
Browser->>createAuthClient: signIn("authentik")
createAuthClient->>apiSignIn: start sign-in request
end
apiSignIn->>Authentik: redirect to OAuth provider
Authentik->>apiSignIn: OAuth callback
apiSignIn->>Browser: session response
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/src/content/docs/`(core)/oauth/authentik.mdx:
- Around line 98-107: The customization example for authentik is using the wrong
API shape: update the `authentik()` provider config in the `createAuth` example
to pass `scope` at the top level instead of nesting it under `authorize.params`.
Use an OIDC-style scope string such as `openid profile email`, and keep the
example aligned with the `authentik` provider options shown in this docs
snippet.
In `@packages/core/src/oauth/authentik.ts`:
- Line 35: The Authentik OpenID issuer is currently hardcoded to a full
discovery URL with a trailing comma, which breaks URL construction in
OpenIDProvider.issuer; update the authentik config in authentiK.ts so issuer is
only the base Authentik URL, and make it deployment-configurable instead of
embedding the host and application slug directly. Use the existing
Authentik/OpenID provider setup to locate the issuer assignment and ensure the
discovery endpoint is still derived by the provider.
- Around line 36-42: The Authentik profile mapping in authentik.ts is dropping
optional claims that are already available on AuthentikProfile and supported by
DefaultUser. Update the profile-to-user mapping in the Authentik provider’s
profile callback to pass through email_verified, nickname, and
preferred_username alongside the existing sub, name, email, and image fields so
downstream consumers receive the full Authentik payload.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: eaf551d9-5151-4f45-a3af-f02caf9bffef
📒 Files selected for processing (2)
docs/src/content/docs/(core)/oauth/authentik.mdxpackages/core/src/oauth/authentik.ts
| export const auth = createAuth({ | ||
| oauth: [ | ||
| authentik({ | ||
| authorize: { | ||
| params: { | ||
| // Override default scopes | ||
| scope: "read:user user:email", | ||
| }, | ||
| }, | ||
| }), |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the referenced docs file and provider implementation.
git ls-files 'docs/src/content/docs/(core)/oauth/authentik.mdx' 'packages/core/src/oauth/authentik.ts' 'packages/core/src/oauth/*.ts' 'packages/core/src/oauth/**/*.ts'
echo '--- authentik docs excerpt ---'
sed -n '80,130p' docs/src/content/docs/\(core\)/oauth/authentik.mdx
echo '--- authentik provider file outline ---'
ast-grep outline packages/core/src/oauth/authentik.ts --view expanded || true
echo '--- provider source excerpt ---'
sed -n '1,220p' packages/core/src/oauth/authentik.ts
echo '--- search for OpenIDProvider definition and authorize/scope fields ---'
rg -n "interface OpenIDProvider|type OpenIDProvider|authorize:|scope\\?" packages/core/src/oauth packages/core/src -g '*.ts'Repository: aura-stack-ts/auth
Length of output: 6054
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the surrounding docs/example more precisely if needed.
wc -l docs/src/content/docs/\(core\)/oauth/authentik.mdx packages/core/src/oauth/authentik.ts || trueRepository: aura-stack-ts/auth
Length of output: 263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '200,250p' packages/core/src/@types/oidc.ts
echo '---'
sed -n '1,140p' packages/core/src/@types/oauth.ts
echo '---'
sed -n '1,120p' packages/core/src/schemas.ts
echo '---'
sed -n '60,110p' packages/core/src/createAuth.ts
echo '---'
sed -n '1,120p' packages/core/src/actions/oidc/authorization-url.tsRepository: aura-stack-ts/auth
Length of output: 12159
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '200,250p' packages/core/src/@types/oidc.ts
echo '---'
sed -n '1,140p' packages/core/src/@types/oauth.ts
echo '---'
sed -n '1,120p' packages/core/src/schemas.ts
echo '---'
sed -n '60,110p' packages/core/src/createAuth.ts
echo '---'
sed -n '1,120p' packages/core/src/actions/oidc/authorization-url.tsRepository: aura-stack-ts/auth
Length of output: 12159
Fix the customization example to use the top-level scope option.
authentik() accepts scope directly on the provider config, not authorize.params, so this example does not match the API. Use an OIDC scope string like openid profile email instead.
Suggested fix
export const auth = createAuth({
oauth: [
authentik({
- authorize: {
- params: {
- // Override default scopes
- scope: "read:user user:email",
- },
- },
+ scope: "openid profile email",
}),
],
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const auth = createAuth({ | |
| oauth: [ | |
| authentik({ | |
| authorize: { | |
| params: { | |
| // Override default scopes | |
| scope: "read:user user:email", | |
| }, | |
| }, | |
| }), | |
| export const auth = createAuth({ | |
| oauth: [ | |
| authentik({ | |
| scope: "openid profile email", | |
| }), |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/content/docs/`(core)/oauth/authentik.mdx around lines 98 - 107, The
customization example for authentik is using the wrong API shape: update the
`authentik()` provider config in the `createAuth` example to pass `scope` at the
top level instead of nesting it under `authorize.params`. Use an OIDC-style
scope string such as `openid profile email`, and keep the example aligned with
the `authentik` provider options shown in this docs snippet.
| return { | ||
| id: "authentik", | ||
| name: "Authentik", | ||
| issuer: "https://authentik.company/application/o/:application_slug/.well-known/openid-configuration,", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '## Files\n'
git ls-files packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts
printf '\n## Outline: authentik.ts\n'
ast-grep outline packages/core/src/oauth/authentik.ts --view expanded || true
printf '\n## Outline: oidc.ts\n'
ast-grep outline packages/core/src/@types/oidc.ts --view expanded || true
printf '\n## Outline: presets.ts\n'
ast-grep outline packages/core/test/presets.ts --view expanded || true
printf '\n## Read relevant slices\n'
for f in packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts; do
echo "===== $f ====="
nl -ba "$f" | sed -n '1,220p'
doneRepository: aura-stack-ts/auth
Length of output: 3128
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '## Search for authentik usage and OIDC contract\n'
rg -n "authentik|issuer:|well-known/openid-configuration|email_verified|nickname|OpenIDProvider<" packages/core -S
printf '\n## Search for preset expectations around profile fields\n'
rg -n "nickname|email_verified|image|email" packages/core/test -SRepository: aura-stack-ts/auth
Length of output: 26883
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '## Files\n'
git ls-files packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts
printf '\n## Outline: authentik.ts\n'
ast-grep outline packages/core/src/oauth/authentik.ts --view expanded || true
printf '\n## Outline: oidc.ts\n'
ast-grep outline packages/core/src/@types/oidc.ts --view expanded || true
printf '\n## Outline: presets.ts\n'
ast-grep outline packages/core/test/presets.ts --view expanded || true
printf '\n## Read relevant slices\n'
for f in packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts; do
echo "===== $f ====="
nl -ba "$f" | sed -n '1,220p'
doneRepository: aura-stack-ts/auth
Length of output: 3128
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '## Search for authentik usage and OIDC contract\n'
rg -n "authentik|issuer:|well-known/openid-configuration|email_verified|nickname|OpenIDProvider<" packages/core -S
printf '\n## Search for preset expectations around profile fields\n'
rg -n "nickname|email_verified|image|email" packages/core/test -SRepository: aura-stack-ts/auth
Length of output: 26883
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts; do
echo "===== $f ====="
awk '{printf "%4d %s\n", NR, $0}' "$f" | sed -n '1,220p'
doneRepository: aura-stack-ts/auth
Length of output: 21690
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "===== authentik provider ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/oauth/authentik.ts | sed -n '1,120p'
echo
echo "===== OIDC provider contract ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/@types/oidc.ts | sed -n '205,230p'
echo
echo "===== preset mapping ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/test/presets.ts | sed -n '1,90p'Repository: aura-stack-ts/auth
Length of output: 5626
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in packages/core/src/oauth/authentik.ts packages/core/src/@types/oidc.ts packages/core/test/presets.ts; do
echo "===== $f ====="
awk '{printf "%4d %s\n", NR, $0}' "$f" | sed -n '1,220p'
doneRepository: aura-stack-ts/auth
Length of output: 21690
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "===== authentik provider ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/oauth/authentik.ts | sed -n '1,120p'
echo
echo "===== OIDC provider contract ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/@types/oidc.ts | sed -n '205,230p'
echo
echo "===== preset mapping ====="
awk '{printf "%4d %s\n", NR, $0}' packages/core/test/presets.ts | sed -n '1,90p'Repository: aura-stack-ts/auth
Length of output: 5626
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "authentik\s*\(" packages/core -SRepository: aura-stack-ts/auth
Length of output: 156
🏁 Script executed:
#!/bin/bash
set -euo pipefail
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/actions/oidc/discovery.ts | sed -n '1,120p'Repository: aura-stack-ts/auth
Length of output: 1987
🏁 Script executed:
#!/bin/bash
set -euo pipefail
awk '{printf "%4d %s\n", NR, $0}' packages/core/src/actions/oidc/resolve-provider.ts | sed -n '1,120p'Repository: aura-stack-ts/auth
Length of output: 2982
Make issuer the base Authentik URL
OpenIDProvider.issuer is appended with /.well-known/openid-configuration, so the current value (.../.well-known/openid-configuration,) produces a broken discovery URL. It also needs to be configurable per deployment instead of hardcoding the host and application slug.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/src/oauth/authentik.ts` at line 35, The Authentik OpenID issuer
is currently hardcoded to a full discovery URL with a trailing comma, which
breaks URL construction in OpenIDProvider.issuer; update the authentik config in
authentiK.ts so issuer is only the base Authentik URL, and make it
deployment-configurable instead of embedding the host and application slug
directly. Use the existing Authentik/OpenID provider setup to locate the issuer
assignment and ensure the discovery endpoint is still derived by the provider.
| profile: (profile) => | ||
| ({ | ||
| sub: profile.sub, | ||
| name: profile.name, | ||
| email: profile.email, | ||
| image: null, | ||
| }) as DefaultUser, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant file and nearby type definitions.
git ls-files packages/core/src/oauth/authentik.ts packages/core/src/** | sed -n '1,120p'
printf '\n--- outline authentik.ts ---\n'
ast-grep outline packages/core/src/oauth/authentik.ts --view expanded || true
printf '\n--- search for DefaultUser and AuthentikProfile ---\n'
rg -n "type DefaultUser|interface DefaultUser|DefaultUser|AuthentikProfile|email_verified|nickname|preferred_username" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 15030
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the relevant file and the type definitions it depends on.
wc -l packages/core/src/oauth/authentik.ts || true
printf '\n--- authentik.ts ---\n'
cat -n packages/core/src/oauth/authentik.ts
printf '\n--- oauth type definitions search ---\n'
rg -n "type DefaultUser|interface DefaultUser|export .*DefaultUser|AuthentikProfile|preferred_username|email_verified|nickname" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 5458
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the shared OIDC/OAuth schema around DefaultUser if found.
files=$(rg -l "DefaultUser|AuthentikProfile|preferred_username|email_verified|nickname" packages/core/src -S || true)
printf '%s\n' "$files"
for f in $files; do
echo "=== $f ==="
wc -l "$f"
doneRepository: aura-stack-ts/auth
Length of output: 2052
🏁 Script executed:
#!/bin/bash
set -euo pipefail
wc -l packages/core/src/oauth/authentik.ts
printf '\n--- authentik.ts ---\n'
sed -n '1,120p' packages/core/src/oauth/authentik.ts
printf '\n--- relevant symbols ---\n'
rg -n "type DefaultUser|interface DefaultUser|export .*DefaultUser|AuthentikProfile|preferred_username|email_verified|nickname" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 5130
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the exact file and the shared user/profile type definitions.
sed -n '1,120p' packages/core/src/oauth/authentik.ts
printf '\n--- search for DefaultUser / profile schema ---\n'
rg -n "AuthentikProfile|email_verified|nickname|preferred_username|DefaultUser" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 12727
🌐 Web query:
"AuthentikProfile email_verified nickname DefaultUser oauth auth package"
💡 Result:
In authentik, claims such as email_verified, nickname, and other profile information are managed via Scope Mappings in an OAuth2/OIDC Provider [1]. These claims are not static; they are dynamically generated using Python expressions defined in the provider's property mappings [1][2]. Key details regarding your query include: 1. email_verified Claim: Historically, authentik defaulted email_verified to True [3][4]. However, as of release 2025.10, this defaults to False because authentik does not have an internal mechanism to verify email addresses by default [3][1]. If your application requires this to be True, you can create a custom scope mapping or modify an existing one to return a hardcoded True value, or better, map it to a user attribute (e.g., request.user.attributes.get("email_verified", False)) that you manage elsewhere [3]. 2. nickname Claim: The nickname claim is typically included in the default OAuth Mapping: OpenID 'profile' scope [2]. The standard expression for this mapping is: return { "name": request.user.name, "given_name": request.user.name, "preferred_username": request.user.username, "nickname": request.user.username, "groups": [group.name for group in request.user.groups.all], } 3. DefaultUser and Package Context: There is no "DefaultUser" object in the OAuth context; rather, the mapping has access to a request object, specifically request.user, which represents the user currently authenticating [3][1][2]. This allows you to pull attributes, usernames, or groups directly from the user's profile [5][2][6]. 4. Implementation: To customize these claims, you must: * Navigate to Customization > Property Mappings in the authentik admin interface [3]. * Create or edit an OAuth2 Scope Mapping [1]. * Use the Python expression syntax (as shown above) to return a dictionary of claims [1]. * Assign this mapping to your specific OAuth2 Provider under the 'Property mappings' field [1][7]. * Ensure the client application requests the corresponding scope (e.g., 'profile' or 'email') when initiating the OAuth flow [3][7]. If you are using default setups, these mappings are managed by blueprints [2][8]. If you find your scopes are missing or behaving unexpectedly, verify that the default system blueprints are enabled in your instance [2][8].
Citations:
- 1: https://docs.goauthentik.io/add-secure-apps/providers/property-mappings/
- 2: https://github.com/goauthentik/authentik/blob/main/blueprints/system/providers-oauth2.yaml
- 3: https://docs.goauthentik.io/add-secure-apps/providers/oauth2/
- 4: "email_verified": true by default in oauth2 is potentially unsafe goauthentik/authentik#16205
- 5: User Attributes in Oauth goauthentik/authentik#10935
- 6: Social login claims inside of authentik-issued token goauthentik/authentik#8102
- 7: https://docs.goauthentik.io/add-secure-apps/providers/oauth2/machine_to_machine/
- 8: How to create
email, andprofilescope (previously built in) goauthentik/authentik#3389
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- schemas.ts relevant user shape ---\n'
sed -n '240,280p' packages/core/src/schemas.ts
printf '\n--- any runtime usage of email_verified / nickname / preferred_username ---\n'
rg -n "\b(email_verified|nickname|preferred_username)\b" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 247
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- schemas.ts relevant user shape ---\n'
sed -n '240,280p' packages/core/src/schemas.ts
printf '\n--- any runtime usage of email_verified / nickname / preferred_username ---\n'
rg -n "\b(email_verified|nickname|preferred_username)\b" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 247
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- schemas.ts relevant user shape ---\n'
sed -n '240,280p' packages/core/src/schemas.ts
printf '\n--- any runtime usage of email_verified / nickname / preferred_username ---\n'
rg -n "\b(email_verified|nickname|preferred_username)\b" packages/core/src -SRepository: aura-stack-ts/auth
Length of output: 247
Forward Authentik’s optional claims into the mapped user. email_verified, nickname, and preferred_username are already on AuthentikProfile and supported by the shared user schema, so mapping them through keeps Authentik payloads consistent for consumers that rely on verified-email or display-name fallbacks.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/src/oauth/authentik.ts` around lines 36 - 42, The Authentik
profile mapping in authentik.ts is dropping optional claims that are already
available on AuthentikProfile and supported by DefaultUser. Update the
profile-to-user mapping in the Authentik provider’s profile callback to pass
through email_verified, nickname, and preferred_username alongside the existing
sub, name, email, and image fields so downstream consumers receive the full
Authentik payload.
Description
This pull request adds support for the Authentik OpenID Connect (OIDC) provider to the list of authentication providers available in Aura Auth.
This is the third OIDC provider supported by Aura Auth. Additional OAuth/OIDC providers will be added in future releases to provide broader coverage of commonly used identity providers for web applications.
Usage
Note
This PR will remain in draft status until the Authentik OIDC provider has been fully validated with Aura Auth.
While the implementation passes the basic authentication flows and core use cases, it has not yet been comprehensively tested. Additional verification is required to ensure all provider-specific behaviors work as expected and to identify any edge cases before the feature is considered production-ready.
On the other hand, the Authentik provider requires a custom issuer URL, where the
application_slugmust be included as the last path segment. While implementing this provider, I identified an opportunity to improve the developer experience by automatically resolving and loading the required OIDC configuration, reducing the amount of manual setup needed from users.