Skip to content

feat(oidc): add Authentik OpenID Connect Provider#199

Draft
halvaradop wants to merge 1 commit into
masterfrom
feat/add-authentik-oidc
Draft

feat(oidc): add Authentik OpenID Connect Provider#199
halvaradop wants to merge 1 commit into
masterfrom
feat/add-authentik-oidc

Conversation

@halvaradop

@halvaradop halvaradop commented Jun 25, 2026

Copy link
Copy Markdown
Member

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

import { createAuth } from "@aura-stack/auth"

export const auth = createAuth({
  oauth: ["authentik"],
})

export const { handlers } = auth

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_slug must 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.

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
auth Ready Ready Preview, Comment Jun 25, 2026 7:43pm

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an Authentik OpenID provider and a guide covering registration, configuration, sign-in initiation, and session retrieval.

Changes

Authentik OAuth integration

Layer / File(s) Summary
Provider contract and mapping
packages/core/src/oauth/authentik.ts
Defines AuthentikProfile, adds the authentik provider factory, and maps sub, name, and email into the returned user object.
Setup and config guide
docs/src/content/docs/(core)/oauth/authentik.mdx
Adds the guide frontmatter, app registration steps, installation command, environment variables, and auth.ts example.
Sign-in and session usage
docs/src/content/docs/(core)/oauth/authentik.mdx
Adds provider customization examples, sign-in initiation paths, client and server session access examples, and resource links.

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
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

oauth

Poem

A bunny hopped through Authentik light,
With signIn trails and sessions bright.
One nibble of config,
One joyful OAuth trick—
And carrots of docs took flight. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Authentik OIDC provider support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-authentik-oidc

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@halvaradop halvaradop added the oauth Changes related to OAuth flows, providers, tokens, or authentication integration. label Jun 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 99a5419 and 96fd09f.

📒 Files selected for processing (2)
  • docs/src/content/docs/(core)/oauth/authentik.mdx
  • packages/core/src/oauth/authentik.ts

Comment on lines +98 to +107
export const auth = createAuth({
oauth: [
authentik({
authorize: {
params: {
// Override default scopes
scope: "read:user user:email",
},
},
}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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 || true

Repository: 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.ts

Repository: 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.ts

Repository: 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.

Suggested change
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,",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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'
done

Repository: 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 -S

Repository: 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'
done

Repository: 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 -S

Repository: 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'
done

Repository: 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'
done

Repository: 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 -S

Repository: 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.

Comment on lines +36 to +42
profile: (profile) =>
({
sub: profile.sub,
name: profile.name,
email: profile.email,
image: null,
}) as DefaultUser,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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 -S

Repository: 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 -S

Repository: 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"
done

Repository: 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 -S

Repository: 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 -S

Repository: 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:


🏁 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 -S

Repository: 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 -S

Repository: 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 -S

Repository: 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.

@halvaradop halvaradop marked this pull request as draft June 25, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

oauth Changes related to OAuth flows, providers, tokens, or authentication integration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant