Skip to content

Commit 328b758

Browse files
committed
feat: support self-hosted ory via kratos admin url
1 parent 4af7723 commit 328b758

3 files changed

Lines changed: 37 additions & 11 deletions

File tree

scripts/check-app-env.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,25 @@ import { clientSchema, serverSchema, validateEnv } from '../src/lib/env'
55
const projectDir = process.cwd()
66
loadEnvConfig(projectDir)
77

8+
// Always required when AUTH_PROVIDER=ory, regardless of deploy target.
89
const oryRequiredEnvVars = [
910
'AUTH_SECRET',
1011
'ORY_SDK_URL',
1112
'ORY_OAUTH2_CLIENT_ID',
1213
'ORY_OAUTH2_CLIENT_SECRET',
1314
'ORY_OAUTH2_AUDIENCE',
14-
'ORY_PROJECT_API_TOKEN',
1515
'DASHBOARD_API_ADMIN_TOKEN',
1616
] as const
1717

18+
// Identity admin surface: pick exactly one.
19+
// - ORY_PROJECT_API_TOKEN: Ory Network. Bearer for the unified SDK host.
20+
// - ORY_KRATOS_ADMIN_URL: self-hosted Kratos admin (gated by network).
21+
// At least one must be set so IdentityApi calls can resolve.
22+
const oryIdentityAdminEnvVars = [
23+
'ORY_PROJECT_API_TOKEN',
24+
'ORY_KRATOS_ADMIN_URL',
25+
] as const
26+
1827
const schema = serverSchema
1928
.merge(clientSchema)
2029
.refine(
@@ -81,6 +90,17 @@ const schema = serverSchema
8190
path: ['AUTH_PROVIDER'],
8291
})
8392
}
93+
94+
const hasIdentityAdmin = oryIdentityAdminEnvVars.some(
95+
(envVar) => !!data[envVar]
96+
)
97+
if (!hasIdentityAdmin) {
98+
ctx.addIssue({
99+
code: z.ZodIssueCode.custom,
100+
message: `AUTH_PROVIDER=ory requires either ${oryIdentityAdminEnvVars.join(' (Ory Network) or ')} (self-hosted Kratos admin)`,
101+
path: ['AUTH_PROVIDER'],
102+
})
103+
}
84104
})
85105

86106
validateEnv(schema)

src/core/server/auth/ory/client.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@ import { Configuration, IdentityApi, OAuth2Api } from '@ory/client-fetch'
55
let cachedIdentityApi: IdentityApi | null = null
66
let cachedOAuth2Api: OAuth2Api | null = null
77

8-
// the IdentityApi requires the Ory project admin token (PAT). callers should
9-
// ensure ORY_PROJECT_API_TOKEN is set at deploy time when AUTH_PROVIDER=ory.
8+
// IdentityApi resolution:
9+
// 1. ORY_KRATOS_ADMIN_URL — self-hosted Kratos admin (e.g. local devenv :4434).
10+
// 2. ORY_SDK_URL — Ory Network (identity admin co-located on the SDK host).
11+
//
12+
// The PAT is attached only when configured: Ory Network gates on it,
13+
// self-hosted Kratos admin uses network reachability instead.
1014
export function getOryIdentityApi(): IdentityApi {
1115
if (cachedIdentityApi) return cachedIdentityApi
1216

13-
cachedIdentityApi = new IdentityApi(getOryConfiguration())
17+
cachedIdentityApi = new IdentityApi(
18+
getOryConfiguration(process.env.ORY_KRATOS_ADMIN_URL)
19+
)
20+
1421
return cachedIdentityApi
1522
}
1623

@@ -21,19 +28,17 @@ export function getOryOAuth2Api(): OAuth2Api {
2128
return cachedOAuth2Api
2229
}
2330

24-
function getOryConfiguration(): Configuration {
25-
const basePath = process.env.ORY_SDK_URL
26-
const accessToken = process.env.ORY_PROJECT_API_TOKEN
31+
function getOryConfiguration(basePathOverride?: string): Configuration {
32+
const basePath = basePathOverride ?? process.env.ORY_SDK_URL
2733

2834
if (!basePath) {
2935
throw new Error('ORY_SDK_URL is not configured')
3036
}
31-
if (!accessToken) {
32-
throw new Error('ORY_PROJECT_API_TOKEN is not configured')
33-
}
37+
38+
const accessToken = process.env.ORY_PROJECT_API_TOKEN
3439

3540
return new Configuration({
3641
basePath: basePath.replace(/\/$/, ''),
37-
accessToken,
42+
...(accessToken ? { accessToken } : {}),
3843
})
3944
}

src/lib/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const serverSchema = z.object({
2222
ORY_OAUTH2_CLIENT_SECRET: z.string().min(1).optional(),
2323
ORY_OAUTH2_AUDIENCE: z.string().min(1).optional(),
2424
ORY_PROJECT_API_TOKEN: z.string().min(1).optional(),
25+
ORY_KRATOS_ADMIN_URL: z.url().optional(),
2526

2627
OTEL_SERVICE_NAME: z.string().optional(),
2728
OTEL_EXPORTER_OTLP_ENDPOINT: z.url().optional(),

0 commit comments

Comments
 (0)