@better-auth/sso 1.4.5 → 1.4.6-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +6 -6
- package/dist/index.mjs +115 -107
- package/package.json +4 -4
- package/src/routes/domain-verification.ts +6 -6
- package/src/routes/sso.ts +297 -288
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/sso@1.4.
|
|
2
|
+
> @better-auth/sso@1.4.6-beta.3 build /home/runner/work/better-auth/better-auth/packages/sso
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.
|
|
6
|
-
[34mℹ[39m
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.17.0[22m powered by rolldown [2mv1.0.0-beta.53[22m
|
|
6
|
+
[34mℹ[39m config file: [4m/home/runner/work/better-auth/better-auth/packages/sso/tsdown.config.ts[24m
|
|
7
7
|
[34mℹ[39m entry: [34msrc/index.ts, src/client.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
9
|
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m58.
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m58.73 kB[22m [2m│ gzip: 10.41 kB[22m
|
|
11
11
|
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m [2m 0.15 kB[22m [2m│ gzip: 0.14 kB[22m
|
|
12
12
|
[34mℹ[39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m 0.49 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
13
13
|
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 0.21 kB[22m [2m│ gzip: 0.15 kB[22m
|
|
14
14
|
[34mℹ[39m [2mdist/[22m[32mindex-D-JmJR9N.d.mts[39m [2m25.42 kB[22m [2m│ gzip: 3.95 kB[22m
|
|
15
|
-
[34mℹ[39m 5 files, total:
|
|
16
|
-
[32m✔[39m Build complete in [
|
|
15
|
+
[34mℹ[39m 5 files, total: 85.01 kB
|
|
16
|
+
[32m✔[39m Build complete in [32m10982ms[39m
|
package/dist/index.mjs
CHANGED
|
@@ -10,10 +10,11 @@ import { handleOAuthUserInfo } from "better-auth/oauth2";
|
|
|
10
10
|
import { decodeJwt } from "jose";
|
|
11
11
|
|
|
12
12
|
//#region src/routes/domain-verification.ts
|
|
13
|
+
const domainVerificationBodySchema = z.object({ providerId: z.string() });
|
|
13
14
|
const requestDomainVerification = (options) => {
|
|
14
15
|
return createAuthEndpoint("/sso/request-domain-verification", {
|
|
15
16
|
method: "POST",
|
|
16
|
-
body:
|
|
17
|
+
body: domainVerificationBodySchema,
|
|
17
18
|
metadata: { openapi: {
|
|
18
19
|
summary: "Request a domain verification",
|
|
19
20
|
description: "Request a domain verification for the given SSO provider",
|
|
@@ -90,7 +91,7 @@ const requestDomainVerification = (options) => {
|
|
|
90
91
|
const verifyDomain = (options) => {
|
|
91
92
|
return createAuthEndpoint("/sso/verify-domain", {
|
|
92
93
|
method: "POST",
|
|
93
|
-
body:
|
|
94
|
+
body: domainVerificationBodySchema,
|
|
94
95
|
metadata: { openapi: {
|
|
95
96
|
summary: "Verify the provider domain ownership",
|
|
96
97
|
description: "Verify the provider domain ownership via DNS records",
|
|
@@ -208,13 +209,14 @@ function safeJsonParse(value) {
|
|
|
208
209
|
}
|
|
209
210
|
return null;
|
|
210
211
|
}
|
|
212
|
+
const spMetadataQuerySchema = z.object({
|
|
213
|
+
providerId: z.string(),
|
|
214
|
+
format: z.enum(["xml", "json"]).default("xml")
|
|
215
|
+
});
|
|
211
216
|
const spMetadata = () => {
|
|
212
217
|
return createAuthEndpoint("/sso/saml2/sp/metadata", {
|
|
213
218
|
method: "GET",
|
|
214
|
-
query:
|
|
215
|
-
providerId: z.string(),
|
|
216
|
-
format: z.enum(["xml", "json"]).default("xml")
|
|
217
|
-
}),
|
|
219
|
+
query: spMetadataQuerySchema,
|
|
218
220
|
metadata: { openapi: {
|
|
219
221
|
operationId: "getSSOServiceProviderMetadata",
|
|
220
222
|
summary: "Get Service Provider metadata",
|
|
@@ -244,82 +246,83 @@ const spMetadata = () => {
|
|
|
244
246
|
return new Response(sp.getMetadata(), { headers: { "Content-Type": "application/xml" } });
|
|
245
247
|
});
|
|
246
248
|
};
|
|
249
|
+
const ssoProviderBodySchema = z.object({
|
|
250
|
+
providerId: z.string({}).meta({ description: "The ID of the provider. This is used to identify the provider during login and callback" }),
|
|
251
|
+
issuer: z.string({}).meta({ description: "The issuer of the provider" }),
|
|
252
|
+
domain: z.string({}).meta({ description: "The domain of the provider. This is used for email matching" }),
|
|
253
|
+
oidcConfig: z.object({
|
|
254
|
+
clientId: z.string({}).meta({ description: "The client ID" }),
|
|
255
|
+
clientSecret: z.string({}).meta({ description: "The client secret" }),
|
|
256
|
+
authorizationEndpoint: z.string({}).meta({ description: "The authorization endpoint" }).optional(),
|
|
257
|
+
tokenEndpoint: z.string({}).meta({ description: "The token endpoint" }).optional(),
|
|
258
|
+
userInfoEndpoint: z.string({}).meta({ description: "The user info endpoint" }).optional(),
|
|
259
|
+
tokenEndpointAuthentication: z.enum(["client_secret_post", "client_secret_basic"]).optional(),
|
|
260
|
+
jwksEndpoint: z.string({}).meta({ description: "The JWKS endpoint" }).optional(),
|
|
261
|
+
discoveryEndpoint: z.string().optional(),
|
|
262
|
+
scopes: z.array(z.string(), {}).meta({ description: "The scopes to request. Defaults to ['openid', 'email', 'profile', 'offline_access']" }).optional(),
|
|
263
|
+
pkce: z.boolean({}).meta({ description: "Whether to use PKCE for the authorization flow" }).default(true).optional(),
|
|
264
|
+
mapping: z.object({
|
|
265
|
+
id: z.string({}).meta({ description: "Field mapping for user ID (defaults to 'sub')" }),
|
|
266
|
+
email: z.string({}).meta({ description: "Field mapping for email (defaults to 'email')" }),
|
|
267
|
+
emailVerified: z.string({}).meta({ description: "Field mapping for email verification (defaults to 'email_verified')" }).optional(),
|
|
268
|
+
name: z.string({}).meta({ description: "Field mapping for name (defaults to 'name')" }),
|
|
269
|
+
image: z.string({}).meta({ description: "Field mapping for image (defaults to 'picture')" }).optional(),
|
|
270
|
+
extraFields: z.record(z.string(), z.any()).optional()
|
|
271
|
+
}).optional()
|
|
272
|
+
}).optional(),
|
|
273
|
+
samlConfig: z.object({
|
|
274
|
+
entryPoint: z.string({}).meta({ description: "The entry point of the provider" }),
|
|
275
|
+
cert: z.string({}).meta({ description: "The certificate of the provider" }),
|
|
276
|
+
callbackUrl: z.string({}).meta({ description: "The callback URL of the provider" }),
|
|
277
|
+
audience: z.string().optional(),
|
|
278
|
+
idpMetadata: z.object({
|
|
279
|
+
metadata: z.string().optional(),
|
|
280
|
+
entityID: z.string().optional(),
|
|
281
|
+
cert: z.string().optional(),
|
|
282
|
+
privateKey: z.string().optional(),
|
|
283
|
+
privateKeyPass: z.string().optional(),
|
|
284
|
+
isAssertionEncrypted: z.boolean().optional(),
|
|
285
|
+
encPrivateKey: z.string().optional(),
|
|
286
|
+
encPrivateKeyPass: z.string().optional(),
|
|
287
|
+
singleSignOnService: z.array(z.object({
|
|
288
|
+
Binding: z.string().meta({ description: "The binding type for the SSO service" }),
|
|
289
|
+
Location: z.string().meta({ description: "The URL for the SSO service" })
|
|
290
|
+
})).optional().meta({ description: "Single Sign-On service configuration" })
|
|
291
|
+
}).optional(),
|
|
292
|
+
spMetadata: z.object({
|
|
293
|
+
metadata: z.string().optional(),
|
|
294
|
+
entityID: z.string().optional(),
|
|
295
|
+
binding: z.string().optional(),
|
|
296
|
+
privateKey: z.string().optional(),
|
|
297
|
+
privateKeyPass: z.string().optional(),
|
|
298
|
+
isAssertionEncrypted: z.boolean().optional(),
|
|
299
|
+
encPrivateKey: z.string().optional(),
|
|
300
|
+
encPrivateKeyPass: z.string().optional()
|
|
301
|
+
}),
|
|
302
|
+
wantAssertionsSigned: z.boolean().optional(),
|
|
303
|
+
signatureAlgorithm: z.string().optional(),
|
|
304
|
+
digestAlgorithm: z.string().optional(),
|
|
305
|
+
identifierFormat: z.string().optional(),
|
|
306
|
+
privateKey: z.string().optional(),
|
|
307
|
+
decryptionPvk: z.string().optional(),
|
|
308
|
+
additionalParams: z.record(z.string(), z.any()).optional(),
|
|
309
|
+
mapping: z.object({
|
|
310
|
+
id: z.string({}).meta({ description: "Field mapping for user ID (defaults to 'nameID')" }),
|
|
311
|
+
email: z.string({}).meta({ description: "Field mapping for email (defaults to 'email')" }),
|
|
312
|
+
emailVerified: z.string({}).meta({ description: "Field mapping for email verification" }).optional(),
|
|
313
|
+
name: z.string({}).meta({ description: "Field mapping for name (defaults to 'displayName')" }),
|
|
314
|
+
firstName: z.string({}).meta({ description: "Field mapping for first name (defaults to 'givenName')" }).optional(),
|
|
315
|
+
lastName: z.string({}).meta({ description: "Field mapping for last name (defaults to 'surname')" }).optional(),
|
|
316
|
+
extraFields: z.record(z.string(), z.any()).optional()
|
|
317
|
+
}).optional()
|
|
318
|
+
}).optional(),
|
|
319
|
+
organizationId: z.string({}).meta({ description: "If organization plugin is enabled, the organization id to link the provider to" }).optional(),
|
|
320
|
+
overrideUserInfo: z.boolean({}).meta({ description: "Override user info with the provider info. Defaults to false" }).default(false).optional()
|
|
321
|
+
});
|
|
247
322
|
const registerSSOProvider = (options) => {
|
|
248
323
|
return createAuthEndpoint("/sso/register", {
|
|
249
324
|
method: "POST",
|
|
250
|
-
body:
|
|
251
|
-
providerId: z.string({}).meta({ description: "The ID of the provider. This is used to identify the provider during login and callback" }),
|
|
252
|
-
issuer: z.string({}).meta({ description: "The issuer of the provider" }),
|
|
253
|
-
domain: z.string({}).meta({ description: "The domain of the provider. This is used for email matching" }),
|
|
254
|
-
oidcConfig: z.object({
|
|
255
|
-
clientId: z.string({}).meta({ description: "The client ID" }),
|
|
256
|
-
clientSecret: z.string({}).meta({ description: "The client secret" }),
|
|
257
|
-
authorizationEndpoint: z.string({}).meta({ description: "The authorization endpoint" }).optional(),
|
|
258
|
-
tokenEndpoint: z.string({}).meta({ description: "The token endpoint" }).optional(),
|
|
259
|
-
userInfoEndpoint: z.string({}).meta({ description: "The user info endpoint" }).optional(),
|
|
260
|
-
tokenEndpointAuthentication: z.enum(["client_secret_post", "client_secret_basic"]).optional(),
|
|
261
|
-
jwksEndpoint: z.string({}).meta({ description: "The JWKS endpoint" }).optional(),
|
|
262
|
-
discoveryEndpoint: z.string().optional(),
|
|
263
|
-
scopes: z.array(z.string(), {}).meta({ description: "The scopes to request. Defaults to ['openid', 'email', 'profile', 'offline_access']" }).optional(),
|
|
264
|
-
pkce: z.boolean({}).meta({ description: "Whether to use PKCE for the authorization flow" }).default(true).optional(),
|
|
265
|
-
mapping: z.object({
|
|
266
|
-
id: z.string({}).meta({ description: "Field mapping for user ID (defaults to 'sub')" }),
|
|
267
|
-
email: z.string({}).meta({ description: "Field mapping for email (defaults to 'email')" }),
|
|
268
|
-
emailVerified: z.string({}).meta({ description: "Field mapping for email verification (defaults to 'email_verified')" }).optional(),
|
|
269
|
-
name: z.string({}).meta({ description: "Field mapping for name (defaults to 'name')" }),
|
|
270
|
-
image: z.string({}).meta({ description: "Field mapping for image (defaults to 'picture')" }).optional(),
|
|
271
|
-
extraFields: z.record(z.string(), z.any()).optional()
|
|
272
|
-
}).optional()
|
|
273
|
-
}).optional(),
|
|
274
|
-
samlConfig: z.object({
|
|
275
|
-
entryPoint: z.string({}).meta({ description: "The entry point of the provider" }),
|
|
276
|
-
cert: z.string({}).meta({ description: "The certificate of the provider" }),
|
|
277
|
-
callbackUrl: z.string({}).meta({ description: "The callback URL of the provider" }),
|
|
278
|
-
audience: z.string().optional(),
|
|
279
|
-
idpMetadata: z.object({
|
|
280
|
-
metadata: z.string().optional(),
|
|
281
|
-
entityID: z.string().optional(),
|
|
282
|
-
cert: z.string().optional(),
|
|
283
|
-
privateKey: z.string().optional(),
|
|
284
|
-
privateKeyPass: z.string().optional(),
|
|
285
|
-
isAssertionEncrypted: z.boolean().optional(),
|
|
286
|
-
encPrivateKey: z.string().optional(),
|
|
287
|
-
encPrivateKeyPass: z.string().optional(),
|
|
288
|
-
singleSignOnService: z.array(z.object({
|
|
289
|
-
Binding: z.string().meta({ description: "The binding type for the SSO service" }),
|
|
290
|
-
Location: z.string().meta({ description: "The URL for the SSO service" })
|
|
291
|
-
})).optional().meta({ description: "Single Sign-On service configuration" })
|
|
292
|
-
}).optional(),
|
|
293
|
-
spMetadata: z.object({
|
|
294
|
-
metadata: z.string().optional(),
|
|
295
|
-
entityID: z.string().optional(),
|
|
296
|
-
binding: z.string().optional(),
|
|
297
|
-
privateKey: z.string().optional(),
|
|
298
|
-
privateKeyPass: z.string().optional(),
|
|
299
|
-
isAssertionEncrypted: z.boolean().optional(),
|
|
300
|
-
encPrivateKey: z.string().optional(),
|
|
301
|
-
encPrivateKeyPass: z.string().optional()
|
|
302
|
-
}),
|
|
303
|
-
wantAssertionsSigned: z.boolean().optional(),
|
|
304
|
-
signatureAlgorithm: z.string().optional(),
|
|
305
|
-
digestAlgorithm: z.string().optional(),
|
|
306
|
-
identifierFormat: z.string().optional(),
|
|
307
|
-
privateKey: z.string().optional(),
|
|
308
|
-
decryptionPvk: z.string().optional(),
|
|
309
|
-
additionalParams: z.record(z.string(), z.any()).optional(),
|
|
310
|
-
mapping: z.object({
|
|
311
|
-
id: z.string({}).meta({ description: "Field mapping for user ID (defaults to 'nameID')" }),
|
|
312
|
-
email: z.string({}).meta({ description: "Field mapping for email (defaults to 'email')" }),
|
|
313
|
-
emailVerified: z.string({}).meta({ description: "Field mapping for email verification" }).optional(),
|
|
314
|
-
name: z.string({}).meta({ description: "Field mapping for name (defaults to 'displayName')" }),
|
|
315
|
-
firstName: z.string({}).meta({ description: "Field mapping for first name (defaults to 'givenName')" }).optional(),
|
|
316
|
-
lastName: z.string({}).meta({ description: "Field mapping for last name (defaults to 'surname')" }).optional(),
|
|
317
|
-
extraFields: z.record(z.string(), z.any()).optional()
|
|
318
|
-
}).optional()
|
|
319
|
-
}).optional(),
|
|
320
|
-
organizationId: z.string({}).meta({ description: "If organization plugin is enabled, the organization id to link the provider to" }).optional(),
|
|
321
|
-
overrideUserInfo: z.boolean({}).meta({ description: "Override user info with the provider info. Defaults to false" }).default(false).optional()
|
|
322
|
-
}),
|
|
325
|
+
body: ssoProviderBodySchema,
|
|
323
326
|
use: [sessionMiddleware],
|
|
324
327
|
metadata: { openapi: {
|
|
325
328
|
operationId: "registerSSOProvider",
|
|
@@ -592,22 +595,23 @@ const registerSSOProvider = (options) => {
|
|
|
592
595
|
});
|
|
593
596
|
});
|
|
594
597
|
};
|
|
598
|
+
const signInSSOBodySchema = z.object({
|
|
599
|
+
email: z.string({}).meta({ description: "The email address to sign in with. This is used to identify the issuer to sign in with. It's optional if the issuer is provided" }).optional(),
|
|
600
|
+
organizationSlug: z.string({}).meta({ description: "The slug of the organization to sign in with" }).optional(),
|
|
601
|
+
providerId: z.string({}).meta({ description: "The ID of the provider to sign in with. This can be provided instead of email or issuer" }).optional(),
|
|
602
|
+
domain: z.string({}).meta({ description: "The domain of the provider." }).optional(),
|
|
603
|
+
callbackURL: z.string({}).meta({ description: "The URL to redirect to after login" }),
|
|
604
|
+
errorCallbackURL: z.string({}).meta({ description: "The URL to redirect to after login" }).optional(),
|
|
605
|
+
newUserCallbackURL: z.string({}).meta({ description: "The URL to redirect to after login if the user is new" }).optional(),
|
|
606
|
+
scopes: z.array(z.string(), {}).meta({ description: "Scopes to request from the provider." }).optional(),
|
|
607
|
+
loginHint: z.string({}).meta({ description: "Login hint to send to the identity provider (e.g., email or identifier). If supported, will be sent as 'login_hint'." }).optional(),
|
|
608
|
+
requestSignUp: z.boolean({}).meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(),
|
|
609
|
+
providerType: z.enum(["oidc", "saml"]).optional()
|
|
610
|
+
});
|
|
595
611
|
const signInSSO = (options) => {
|
|
596
612
|
return createAuthEndpoint("/sign-in/sso", {
|
|
597
613
|
method: "POST",
|
|
598
|
-
body:
|
|
599
|
-
email: z.string({}).meta({ description: "The email address to sign in with. This is used to identify the issuer to sign in with. It's optional if the issuer is provided" }).optional(),
|
|
600
|
-
organizationSlug: z.string({}).meta({ description: "The slug of the organization to sign in with" }).optional(),
|
|
601
|
-
providerId: z.string({}).meta({ description: "The ID of the provider to sign in with. This can be provided instead of email or issuer" }).optional(),
|
|
602
|
-
domain: z.string({}).meta({ description: "The domain of the provider." }).optional(),
|
|
603
|
-
callbackURL: z.string({}).meta({ description: "The URL to redirect to after login" }),
|
|
604
|
-
errorCallbackURL: z.string({}).meta({ description: "The URL to redirect to after login" }).optional(),
|
|
605
|
-
newUserCallbackURL: z.string({}).meta({ description: "The URL to redirect to after login if the user is new" }).optional(),
|
|
606
|
-
scopes: z.array(z.string(), {}).meta({ description: "Scopes to request from the provider." }).optional(),
|
|
607
|
-
loginHint: z.string({}).meta({ description: "Login hint to send to the identity provider (e.g., email or identifier). If supported, will be sent as 'login_hint'." }).optional(),
|
|
608
|
-
requestSignUp: z.boolean({}).meta({ description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider" }).optional(),
|
|
609
|
-
providerType: z.enum(["oidc", "saml"]).optional()
|
|
610
|
-
}),
|
|
614
|
+
body: signInSSOBodySchema,
|
|
611
615
|
metadata: { openapi: {
|
|
612
616
|
operationId: "signInWithSSO",
|
|
613
617
|
summary: "Sign in with SSO provider",
|
|
@@ -781,15 +785,16 @@ const signInSSO = (options) => {
|
|
|
781
785
|
throw new APIError("BAD_REQUEST", { message: "Invalid SSO provider" });
|
|
782
786
|
});
|
|
783
787
|
};
|
|
788
|
+
const callbackSSOQuerySchema = z.object({
|
|
789
|
+
code: z.string().optional(),
|
|
790
|
+
state: z.string(),
|
|
791
|
+
error: z.string().optional(),
|
|
792
|
+
error_description: z.string().optional()
|
|
793
|
+
});
|
|
784
794
|
const callbackSSO = (options) => {
|
|
785
795
|
return createAuthEndpoint("/sso/callback/:providerId", {
|
|
786
796
|
method: "GET",
|
|
787
|
-
query:
|
|
788
|
-
code: z.string().optional(),
|
|
789
|
-
state: z.string(),
|
|
790
|
-
error: z.string().optional(),
|
|
791
|
-
error_description: z.string().optional()
|
|
792
|
-
}),
|
|
797
|
+
query: callbackSSOQuerySchema,
|
|
793
798
|
allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"],
|
|
794
799
|
metadata: {
|
|
795
800
|
isAction: false,
|
|
@@ -966,13 +971,14 @@ const callbackSSO = (options) => {
|
|
|
966
971
|
throw ctx.redirect(toRedirectTo);
|
|
967
972
|
});
|
|
968
973
|
};
|
|
974
|
+
const callbackSSOSAMLBodySchema = z.object({
|
|
975
|
+
SAMLResponse: z.string(),
|
|
976
|
+
RelayState: z.string().optional()
|
|
977
|
+
});
|
|
969
978
|
const callbackSSOSAML = (options) => {
|
|
970
979
|
return createAuthEndpoint("/sso/saml2/callback/:providerId", {
|
|
971
980
|
method: "POST",
|
|
972
|
-
body:
|
|
973
|
-
SAMLResponse: z.string(),
|
|
974
|
-
RelayState: z.string().optional()
|
|
975
|
-
}),
|
|
981
|
+
body: callbackSSOSAMLBodySchema,
|
|
976
982
|
metadata: {
|
|
977
983
|
isAction: false,
|
|
978
984
|
allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"],
|
|
@@ -1186,14 +1192,16 @@ const callbackSSOSAML = (options) => {
|
|
|
1186
1192
|
throw ctx.redirect(callbackUrl);
|
|
1187
1193
|
});
|
|
1188
1194
|
};
|
|
1195
|
+
const acsEndpointParamsSchema = z.object({ providerId: z.string().optional() });
|
|
1196
|
+
const acsEndpointBodySchema = z.object({
|
|
1197
|
+
SAMLResponse: z.string(),
|
|
1198
|
+
RelayState: z.string().optional()
|
|
1199
|
+
});
|
|
1189
1200
|
const acsEndpoint = (options) => {
|
|
1190
1201
|
return createAuthEndpoint("/sso/saml2/sp/acs/:providerId", {
|
|
1191
1202
|
method: "POST",
|
|
1192
|
-
params:
|
|
1193
|
-
body:
|
|
1194
|
-
SAMLResponse: z.string(),
|
|
1195
|
-
RelayState: z.string().optional()
|
|
1196
|
-
}),
|
|
1203
|
+
params: acsEndpointParamsSchema,
|
|
1204
|
+
body: acsEndpointBodySchema,
|
|
1197
1205
|
metadata: {
|
|
1198
1206
|
isAction: false,
|
|
1199
1207
|
allowedMediaTypes: ["application/x-www-form-urlencoded", "application/json"],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/sso",
|
|
3
3
|
"author": "Bereket Engida",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.6-beta.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
7
7
|
"homepage": "https://www.better-auth.com/docs/plugins/sso",
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
"body-parser": "^2.2.1",
|
|
65
65
|
"express": "^5.1.0",
|
|
66
66
|
"oauth2-mock-server": "^8.2.0",
|
|
67
|
-
"tsdown": "^0.
|
|
68
|
-
"better-auth": "1.4.
|
|
67
|
+
"tsdown": "^0.17.0",
|
|
68
|
+
"better-auth": "1.4.6-beta.3"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"better-auth": "1.4.
|
|
71
|
+
"better-auth": "1.4.6-beta.3"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"test": "vitest",
|
|
@@ -8,14 +8,16 @@ import { generateRandomString } from "better-auth/crypto";
|
|
|
8
8
|
import * as z from "zod/v4";
|
|
9
9
|
import type { SSOOptions, SSOProvider } from "../types";
|
|
10
10
|
|
|
11
|
+
const domainVerificationBodySchema = z.object({
|
|
12
|
+
providerId: z.string(),
|
|
13
|
+
});
|
|
14
|
+
|
|
11
15
|
export const requestDomainVerification = (options: SSOOptions) => {
|
|
12
16
|
return createAuthEndpoint(
|
|
13
17
|
"/sso/request-domain-verification",
|
|
14
18
|
{
|
|
15
19
|
method: "POST",
|
|
16
|
-
body:
|
|
17
|
-
providerId: z.string(),
|
|
18
|
-
}),
|
|
20
|
+
body: domainVerificationBodySchema,
|
|
19
21
|
metadata: {
|
|
20
22
|
openapi: {
|
|
21
23
|
summary: "Request a domain verification",
|
|
@@ -127,9 +129,7 @@ export const verifyDomain = (options: SSOOptions) => {
|
|
|
127
129
|
"/sso/verify-domain",
|
|
128
130
|
{
|
|
129
131
|
method: "POST",
|
|
130
|
-
body:
|
|
131
|
-
providerId: z.string(),
|
|
132
|
-
}),
|
|
132
|
+
body: domainVerificationBodySchema,
|
|
133
133
|
metadata: {
|
|
134
134
|
openapi: {
|
|
135
135
|
summary: "Verify the provider domain ownership",
|
package/src/routes/sso.ts
CHANGED
|
@@ -52,15 +52,17 @@ function safeJsonParse<T>(value: string | T | null | undefined): T | null {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const spMetadataQuerySchema = z.object({
|
|
56
|
+
providerId: z.string(),
|
|
57
|
+
format: z.enum(["xml", "json"]).default("xml"),
|
|
58
|
+
});
|
|
59
|
+
|
|
55
60
|
export const spMetadata = () => {
|
|
56
61
|
return createAuthEndpoint(
|
|
57
62
|
"/sso/saml2/sp/metadata",
|
|
58
63
|
{
|
|
59
64
|
method: "GET",
|
|
60
|
-
query:
|
|
61
|
-
providerId: z.string(),
|
|
62
|
-
format: z.enum(["xml", "json"]).default("xml"),
|
|
63
|
-
}),
|
|
65
|
+
query: spMetadataQuerySchema,
|
|
64
66
|
metadata: {
|
|
65
67
|
openapi: {
|
|
66
68
|
operationId: "getSSOServiceProviderMetadata",
|
|
@@ -128,213 +130,211 @@ export const spMetadata = () => {
|
|
|
128
130
|
);
|
|
129
131
|
};
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
const ssoProviderBodySchema = z.object({
|
|
134
|
+
providerId: z.string({}).meta({
|
|
135
|
+
description:
|
|
136
|
+
"The ID of the provider. This is used to identify the provider during login and callback",
|
|
137
|
+
}),
|
|
138
|
+
issuer: z.string({}).meta({
|
|
139
|
+
description: "The issuer of the provider",
|
|
140
|
+
}),
|
|
141
|
+
domain: z.string({}).meta({
|
|
142
|
+
description: "The domain of the provider. This is used for email matching",
|
|
143
|
+
}),
|
|
144
|
+
oidcConfig: z
|
|
145
|
+
.object({
|
|
146
|
+
clientId: z.string({}).meta({
|
|
147
|
+
description: "The client ID",
|
|
148
|
+
}),
|
|
149
|
+
clientSecret: z.string({}).meta({
|
|
150
|
+
description: "The client secret",
|
|
151
|
+
}),
|
|
152
|
+
authorizationEndpoint: z
|
|
153
|
+
.string({})
|
|
154
|
+
.meta({
|
|
155
|
+
description: "The authorization endpoint",
|
|
156
|
+
})
|
|
157
|
+
.optional(),
|
|
158
|
+
tokenEndpoint: z
|
|
159
|
+
.string({})
|
|
160
|
+
.meta({
|
|
161
|
+
description: "The token endpoint",
|
|
162
|
+
})
|
|
163
|
+
.optional(),
|
|
164
|
+
userInfoEndpoint: z
|
|
165
|
+
.string({})
|
|
166
|
+
.meta({
|
|
167
|
+
description: "The user info endpoint",
|
|
168
|
+
})
|
|
169
|
+
.optional(),
|
|
170
|
+
tokenEndpointAuthentication: z
|
|
171
|
+
.enum(["client_secret_post", "client_secret_basic"])
|
|
172
|
+
.optional(),
|
|
173
|
+
jwksEndpoint: z
|
|
174
|
+
.string({})
|
|
175
|
+
.meta({
|
|
176
|
+
description: "The JWKS endpoint",
|
|
177
|
+
})
|
|
178
|
+
.optional(),
|
|
179
|
+
discoveryEndpoint: z.string().optional(),
|
|
180
|
+
scopes: z
|
|
181
|
+
.array(z.string(), {})
|
|
182
|
+
.meta({
|
|
145
183
|
description:
|
|
146
|
-
"The
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
184
|
+
"The scopes to request. Defaults to ['openid', 'email', 'profile', 'offline_access']",
|
|
185
|
+
})
|
|
186
|
+
.optional(),
|
|
187
|
+
pkce: z
|
|
188
|
+
.boolean({})
|
|
189
|
+
.meta({
|
|
190
|
+
description: "Whether to use PKCE for the authorization flow",
|
|
191
|
+
})
|
|
192
|
+
.default(true)
|
|
193
|
+
.optional(),
|
|
194
|
+
mapping: z
|
|
195
|
+
.object({
|
|
196
|
+
id: z.string({}).meta({
|
|
197
|
+
description: "Field mapping for user ID (defaults to 'sub')",
|
|
198
|
+
}),
|
|
199
|
+
email: z.string({}).meta({
|
|
200
|
+
description: "Field mapping for email (defaults to 'email')",
|
|
201
|
+
}),
|
|
202
|
+
emailVerified: z
|
|
203
|
+
.string({})
|
|
204
|
+
.meta({
|
|
205
|
+
description:
|
|
206
|
+
"Field mapping for email verification (defaults to 'email_verified')",
|
|
207
|
+
})
|
|
208
|
+
.optional(),
|
|
209
|
+
name: z.string({}).meta({
|
|
210
|
+
description: "Field mapping for name (defaults to 'name')",
|
|
211
|
+
}),
|
|
212
|
+
image: z
|
|
213
|
+
.string({})
|
|
214
|
+
.meta({
|
|
215
|
+
description: "Field mapping for image (defaults to 'picture')",
|
|
216
|
+
})
|
|
217
|
+
.optional(),
|
|
218
|
+
extraFields: z.record(z.string(), z.any()).optional(),
|
|
219
|
+
})
|
|
220
|
+
.optional(),
|
|
221
|
+
})
|
|
222
|
+
.optional(),
|
|
223
|
+
samlConfig: z
|
|
224
|
+
.object({
|
|
225
|
+
entryPoint: z.string({}).meta({
|
|
226
|
+
description: "The entry point of the provider",
|
|
227
|
+
}),
|
|
228
|
+
cert: z.string({}).meta({
|
|
229
|
+
description: "The certificate of the provider",
|
|
230
|
+
}),
|
|
231
|
+
callbackUrl: z.string({}).meta({
|
|
232
|
+
description: "The callback URL of the provider",
|
|
233
|
+
}),
|
|
234
|
+
audience: z.string().optional(),
|
|
235
|
+
idpMetadata: z
|
|
236
|
+
.object({
|
|
237
|
+
metadata: z.string().optional(),
|
|
238
|
+
entityID: z.string().optional(),
|
|
239
|
+
cert: z.string().optional(),
|
|
240
|
+
privateKey: z.string().optional(),
|
|
241
|
+
privateKeyPass: z.string().optional(),
|
|
242
|
+
isAssertionEncrypted: z.boolean().optional(),
|
|
243
|
+
encPrivateKey: z.string().optional(),
|
|
244
|
+
encPrivateKeyPass: z.string().optional(),
|
|
245
|
+
singleSignOnService: z
|
|
246
|
+
.array(
|
|
247
|
+
z.object({
|
|
248
|
+
Binding: z.string().meta({
|
|
249
|
+
description: "The binding type for the SSO service",
|
|
205
250
|
}),
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
.meta({
|
|
209
|
-
description:
|
|
210
|
-
"Field mapping for email verification (defaults to 'email_verified')",
|
|
211
|
-
})
|
|
212
|
-
.optional(),
|
|
213
|
-
name: z.string({}).meta({
|
|
214
|
-
description: "Field mapping for name (defaults to 'name')",
|
|
251
|
+
Location: z.string().meta({
|
|
252
|
+
description: "The URL for the SSO service",
|
|
215
253
|
}),
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
})
|
|
222
|
-
.optional(),
|
|
223
|
-
extraFields: z.record(z.string(), z.any()).optional(),
|
|
224
|
-
})
|
|
225
|
-
.optional(),
|
|
226
|
-
})
|
|
227
|
-
.optional(),
|
|
228
|
-
samlConfig: z
|
|
229
|
-
.object({
|
|
230
|
-
entryPoint: z.string({}).meta({
|
|
231
|
-
description: "The entry point of the provider",
|
|
232
|
-
}),
|
|
233
|
-
cert: z.string({}).meta({
|
|
234
|
-
description: "The certificate of the provider",
|
|
235
|
-
}),
|
|
236
|
-
callbackUrl: z.string({}).meta({
|
|
237
|
-
description: "The callback URL of the provider",
|
|
238
|
-
}),
|
|
239
|
-
audience: z.string().optional(),
|
|
240
|
-
idpMetadata: z
|
|
241
|
-
.object({
|
|
242
|
-
metadata: z.string().optional(),
|
|
243
|
-
entityID: z.string().optional(),
|
|
244
|
-
cert: z.string().optional(),
|
|
245
|
-
privateKey: z.string().optional(),
|
|
246
|
-
privateKeyPass: z.string().optional(),
|
|
247
|
-
isAssertionEncrypted: z.boolean().optional(),
|
|
248
|
-
encPrivateKey: z.string().optional(),
|
|
249
|
-
encPrivateKeyPass: z.string().optional(),
|
|
250
|
-
singleSignOnService: z
|
|
251
|
-
.array(
|
|
252
|
-
z.object({
|
|
253
|
-
Binding: z.string().meta({
|
|
254
|
-
description: "The binding type for the SSO service",
|
|
255
|
-
}),
|
|
256
|
-
Location: z.string().meta({
|
|
257
|
-
description: "The URL for the SSO service",
|
|
258
|
-
}),
|
|
259
|
-
}),
|
|
260
|
-
)
|
|
261
|
-
.optional()
|
|
262
|
-
.meta({
|
|
263
|
-
description: "Single Sign-On service configuration",
|
|
264
|
-
}),
|
|
265
|
-
})
|
|
266
|
-
.optional(),
|
|
267
|
-
spMetadata: z.object({
|
|
268
|
-
metadata: z.string().optional(),
|
|
269
|
-
entityID: z.string().optional(),
|
|
270
|
-
binding: z.string().optional(),
|
|
271
|
-
privateKey: z.string().optional(),
|
|
272
|
-
privateKeyPass: z.string().optional(),
|
|
273
|
-
isAssertionEncrypted: z.boolean().optional(),
|
|
274
|
-
encPrivateKey: z.string().optional(),
|
|
275
|
-
encPrivateKeyPass: z.string().optional(),
|
|
254
|
+
}),
|
|
255
|
+
)
|
|
256
|
+
.optional()
|
|
257
|
+
.meta({
|
|
258
|
+
description: "Single Sign-On service configuration",
|
|
276
259
|
}),
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"Field mapping for user ID (defaults to 'nameID')",
|
|
289
|
-
}),
|
|
290
|
-
email: z.string({}).meta({
|
|
291
|
-
description: "Field mapping for email (defaults to 'email')",
|
|
292
|
-
}),
|
|
293
|
-
emailVerified: z
|
|
294
|
-
.string({})
|
|
295
|
-
.meta({
|
|
296
|
-
description: "Field mapping for email verification",
|
|
297
|
-
})
|
|
298
|
-
.optional(),
|
|
299
|
-
name: z.string({}).meta({
|
|
300
|
-
description:
|
|
301
|
-
"Field mapping for name (defaults to 'displayName')",
|
|
302
|
-
}),
|
|
303
|
-
firstName: z
|
|
304
|
-
.string({})
|
|
305
|
-
.meta({
|
|
306
|
-
description:
|
|
307
|
-
"Field mapping for first name (defaults to 'givenName')",
|
|
308
|
-
})
|
|
309
|
-
.optional(),
|
|
310
|
-
lastName: z
|
|
311
|
-
.string({})
|
|
312
|
-
.meta({
|
|
313
|
-
description:
|
|
314
|
-
"Field mapping for last name (defaults to 'surname')",
|
|
315
|
-
})
|
|
316
|
-
.optional(),
|
|
317
|
-
extraFields: z.record(z.string(), z.any()).optional(),
|
|
318
|
-
})
|
|
319
|
-
.optional(),
|
|
320
|
-
})
|
|
321
|
-
.optional(),
|
|
322
|
-
organizationId: z
|
|
323
|
-
.string({})
|
|
324
|
-
.meta({
|
|
325
|
-
description:
|
|
326
|
-
"If organization plugin is enabled, the organization id to link the provider to",
|
|
327
|
-
})
|
|
328
|
-
.optional(),
|
|
329
|
-
overrideUserInfo: z
|
|
330
|
-
.boolean({})
|
|
331
|
-
.meta({
|
|
332
|
-
description:
|
|
333
|
-
"Override user info with the provider info. Defaults to false",
|
|
334
|
-
})
|
|
335
|
-
.default(false)
|
|
336
|
-
.optional(),
|
|
260
|
+
})
|
|
261
|
+
.optional(),
|
|
262
|
+
spMetadata: z.object({
|
|
263
|
+
metadata: z.string().optional(),
|
|
264
|
+
entityID: z.string().optional(),
|
|
265
|
+
binding: z.string().optional(),
|
|
266
|
+
privateKey: z.string().optional(),
|
|
267
|
+
privateKeyPass: z.string().optional(),
|
|
268
|
+
isAssertionEncrypted: z.boolean().optional(),
|
|
269
|
+
encPrivateKey: z.string().optional(),
|
|
270
|
+
encPrivateKeyPass: z.string().optional(),
|
|
337
271
|
}),
|
|
272
|
+
wantAssertionsSigned: z.boolean().optional(),
|
|
273
|
+
signatureAlgorithm: z.string().optional(),
|
|
274
|
+
digestAlgorithm: z.string().optional(),
|
|
275
|
+
identifierFormat: z.string().optional(),
|
|
276
|
+
privateKey: z.string().optional(),
|
|
277
|
+
decryptionPvk: z.string().optional(),
|
|
278
|
+
additionalParams: z.record(z.string(), z.any()).optional(),
|
|
279
|
+
mapping: z
|
|
280
|
+
.object({
|
|
281
|
+
id: z.string({}).meta({
|
|
282
|
+
description: "Field mapping for user ID (defaults to 'nameID')",
|
|
283
|
+
}),
|
|
284
|
+
email: z.string({}).meta({
|
|
285
|
+
description: "Field mapping for email (defaults to 'email')",
|
|
286
|
+
}),
|
|
287
|
+
emailVerified: z
|
|
288
|
+
.string({})
|
|
289
|
+
.meta({
|
|
290
|
+
description: "Field mapping for email verification",
|
|
291
|
+
})
|
|
292
|
+
.optional(),
|
|
293
|
+
name: z.string({}).meta({
|
|
294
|
+
description: "Field mapping for name (defaults to 'displayName')",
|
|
295
|
+
}),
|
|
296
|
+
firstName: z
|
|
297
|
+
.string({})
|
|
298
|
+
.meta({
|
|
299
|
+
description:
|
|
300
|
+
"Field mapping for first name (defaults to 'givenName')",
|
|
301
|
+
})
|
|
302
|
+
.optional(),
|
|
303
|
+
lastName: z
|
|
304
|
+
.string({})
|
|
305
|
+
.meta({
|
|
306
|
+
description:
|
|
307
|
+
"Field mapping for last name (defaults to 'surname')",
|
|
308
|
+
})
|
|
309
|
+
.optional(),
|
|
310
|
+
extraFields: z.record(z.string(), z.any()).optional(),
|
|
311
|
+
})
|
|
312
|
+
.optional(),
|
|
313
|
+
})
|
|
314
|
+
.optional(),
|
|
315
|
+
organizationId: z
|
|
316
|
+
.string({})
|
|
317
|
+
.meta({
|
|
318
|
+
description:
|
|
319
|
+
"If organization plugin is enabled, the organization id to link the provider to",
|
|
320
|
+
})
|
|
321
|
+
.optional(),
|
|
322
|
+
overrideUserInfo: z
|
|
323
|
+
.boolean({})
|
|
324
|
+
.meta({
|
|
325
|
+
description:
|
|
326
|
+
"Override user info with the provider info. Defaults to false",
|
|
327
|
+
})
|
|
328
|
+
.default(false)
|
|
329
|
+
.optional(),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
export const registerSSOProvider = <O extends SSOOptions>(options: O) => {
|
|
333
|
+
return createAuthEndpoint(
|
|
334
|
+
"/sso/register",
|
|
335
|
+
{
|
|
336
|
+
method: "POST",
|
|
337
|
+
body: ssoProviderBodySchema,
|
|
338
338
|
use: [sessionMiddleware],
|
|
339
339
|
metadata: {
|
|
340
340
|
openapi: {
|
|
@@ -699,76 +699,77 @@ export const registerSSOProvider = <O extends SSOOptions>(options: O) => {
|
|
|
699
699
|
);
|
|
700
700
|
};
|
|
701
701
|
|
|
702
|
+
const signInSSOBodySchema = z.object({
|
|
703
|
+
email: z
|
|
704
|
+
.string({})
|
|
705
|
+
.meta({
|
|
706
|
+
description:
|
|
707
|
+
"The email address to sign in with. This is used to identify the issuer to sign in with. It's optional if the issuer is provided",
|
|
708
|
+
})
|
|
709
|
+
.optional(),
|
|
710
|
+
organizationSlug: z
|
|
711
|
+
.string({})
|
|
712
|
+
.meta({
|
|
713
|
+
description: "The slug of the organization to sign in with",
|
|
714
|
+
})
|
|
715
|
+
.optional(),
|
|
716
|
+
providerId: z
|
|
717
|
+
.string({})
|
|
718
|
+
.meta({
|
|
719
|
+
description:
|
|
720
|
+
"The ID of the provider to sign in with. This can be provided instead of email or issuer",
|
|
721
|
+
})
|
|
722
|
+
.optional(),
|
|
723
|
+
domain: z
|
|
724
|
+
.string({})
|
|
725
|
+
.meta({
|
|
726
|
+
description: "The domain of the provider.",
|
|
727
|
+
})
|
|
728
|
+
.optional(),
|
|
729
|
+
callbackURL: z.string({}).meta({
|
|
730
|
+
description: "The URL to redirect to after login",
|
|
731
|
+
}),
|
|
732
|
+
errorCallbackURL: z
|
|
733
|
+
.string({})
|
|
734
|
+
.meta({
|
|
735
|
+
description: "The URL to redirect to after login",
|
|
736
|
+
})
|
|
737
|
+
.optional(),
|
|
738
|
+
newUserCallbackURL: z
|
|
739
|
+
.string({})
|
|
740
|
+
.meta({
|
|
741
|
+
description: "The URL to redirect to after login if the user is new",
|
|
742
|
+
})
|
|
743
|
+
.optional(),
|
|
744
|
+
scopes: z
|
|
745
|
+
.array(z.string(), {})
|
|
746
|
+
.meta({
|
|
747
|
+
description: "Scopes to request from the provider.",
|
|
748
|
+
})
|
|
749
|
+
.optional(),
|
|
750
|
+
loginHint: z
|
|
751
|
+
.string({})
|
|
752
|
+
.meta({
|
|
753
|
+
description:
|
|
754
|
+
"Login hint to send to the identity provider (e.g., email or identifier). If supported, will be sent as 'login_hint'.",
|
|
755
|
+
})
|
|
756
|
+
.optional(),
|
|
757
|
+
requestSignUp: z
|
|
758
|
+
.boolean({})
|
|
759
|
+
.meta({
|
|
760
|
+
description:
|
|
761
|
+
"Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider",
|
|
762
|
+
})
|
|
763
|
+
.optional(),
|
|
764
|
+
providerType: z.enum(["oidc", "saml"]).optional(),
|
|
765
|
+
});
|
|
766
|
+
|
|
702
767
|
export const signInSSO = (options?: SSOOptions) => {
|
|
703
768
|
return createAuthEndpoint(
|
|
704
769
|
"/sign-in/sso",
|
|
705
770
|
{
|
|
706
771
|
method: "POST",
|
|
707
|
-
body:
|
|
708
|
-
email: z
|
|
709
|
-
.string({})
|
|
710
|
-
.meta({
|
|
711
|
-
description:
|
|
712
|
-
"The email address to sign in with. This is used to identify the issuer to sign in with. It's optional if the issuer is provided",
|
|
713
|
-
})
|
|
714
|
-
.optional(),
|
|
715
|
-
organizationSlug: z
|
|
716
|
-
.string({})
|
|
717
|
-
.meta({
|
|
718
|
-
description: "The slug of the organization to sign in with",
|
|
719
|
-
})
|
|
720
|
-
.optional(),
|
|
721
|
-
providerId: z
|
|
722
|
-
.string({})
|
|
723
|
-
.meta({
|
|
724
|
-
description:
|
|
725
|
-
"The ID of the provider to sign in with. This can be provided instead of email or issuer",
|
|
726
|
-
})
|
|
727
|
-
.optional(),
|
|
728
|
-
domain: z
|
|
729
|
-
.string({})
|
|
730
|
-
.meta({
|
|
731
|
-
description: "The domain of the provider.",
|
|
732
|
-
})
|
|
733
|
-
.optional(),
|
|
734
|
-
callbackURL: z.string({}).meta({
|
|
735
|
-
description: "The URL to redirect to after login",
|
|
736
|
-
}),
|
|
737
|
-
errorCallbackURL: z
|
|
738
|
-
.string({})
|
|
739
|
-
.meta({
|
|
740
|
-
description: "The URL to redirect to after login",
|
|
741
|
-
})
|
|
742
|
-
.optional(),
|
|
743
|
-
newUserCallbackURL: z
|
|
744
|
-
.string({})
|
|
745
|
-
.meta({
|
|
746
|
-
description:
|
|
747
|
-
"The URL to redirect to after login if the user is new",
|
|
748
|
-
})
|
|
749
|
-
.optional(),
|
|
750
|
-
scopes: z
|
|
751
|
-
.array(z.string(), {})
|
|
752
|
-
.meta({
|
|
753
|
-
description: "Scopes to request from the provider.",
|
|
754
|
-
})
|
|
755
|
-
.optional(),
|
|
756
|
-
loginHint: z
|
|
757
|
-
.string({})
|
|
758
|
-
.meta({
|
|
759
|
-
description:
|
|
760
|
-
"Login hint to send to the identity provider (e.g., email or identifier). If supported, will be sent as 'login_hint'.",
|
|
761
|
-
})
|
|
762
|
-
.optional(),
|
|
763
|
-
requestSignUp: z
|
|
764
|
-
.boolean({})
|
|
765
|
-
.meta({
|
|
766
|
-
description:
|
|
767
|
-
"Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider",
|
|
768
|
-
})
|
|
769
|
-
.optional(),
|
|
770
|
-
providerType: z.enum(["oidc", "saml"]).optional(),
|
|
771
|
-
}),
|
|
772
|
+
body: signInSSOBodySchema,
|
|
772
773
|
metadata: {
|
|
773
774
|
openapi: {
|
|
774
775
|
operationId: "signInWithSSO",
|
|
@@ -1101,17 +1102,19 @@ export const signInSSO = (options?: SSOOptions) => {
|
|
|
1101
1102
|
);
|
|
1102
1103
|
};
|
|
1103
1104
|
|
|
1105
|
+
const callbackSSOQuerySchema = z.object({
|
|
1106
|
+
code: z.string().optional(),
|
|
1107
|
+
state: z.string(),
|
|
1108
|
+
error: z.string().optional(),
|
|
1109
|
+
error_description: z.string().optional(),
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1104
1112
|
export const callbackSSO = (options?: SSOOptions) => {
|
|
1105
1113
|
return createAuthEndpoint(
|
|
1106
1114
|
"/sso/callback/:providerId",
|
|
1107
1115
|
{
|
|
1108
1116
|
method: "GET",
|
|
1109
|
-
query:
|
|
1110
|
-
code: z.string().optional(),
|
|
1111
|
-
state: z.string(),
|
|
1112
|
-
error: z.string().optional(),
|
|
1113
|
-
error_description: z.string().optional(),
|
|
1114
|
-
}),
|
|
1117
|
+
query: callbackSSOQuerySchema,
|
|
1115
1118
|
allowedMediaTypes: [
|
|
1116
1119
|
"application/x-www-form-urlencoded",
|
|
1117
1120
|
"application/json",
|
|
@@ -1468,15 +1471,17 @@ export const callbackSSO = (options?: SSOOptions) => {
|
|
|
1468
1471
|
);
|
|
1469
1472
|
};
|
|
1470
1473
|
|
|
1474
|
+
const callbackSSOSAMLBodySchema = z.object({
|
|
1475
|
+
SAMLResponse: z.string(),
|
|
1476
|
+
RelayState: z.string().optional(),
|
|
1477
|
+
});
|
|
1478
|
+
|
|
1471
1479
|
export const callbackSSOSAML = (options?: SSOOptions) => {
|
|
1472
1480
|
return createAuthEndpoint(
|
|
1473
1481
|
"/sso/saml2/callback/:providerId",
|
|
1474
1482
|
{
|
|
1475
1483
|
method: "POST",
|
|
1476
|
-
body:
|
|
1477
|
-
SAMLResponse: z.string(),
|
|
1478
|
-
RelayState: z.string().optional(),
|
|
1479
|
-
}),
|
|
1484
|
+
body: callbackSSOSAMLBodySchema,
|
|
1480
1485
|
metadata: {
|
|
1481
1486
|
isAction: false,
|
|
1482
1487
|
allowedMediaTypes: [
|
|
@@ -1815,18 +1820,22 @@ export const callbackSSOSAML = (options?: SSOOptions) => {
|
|
|
1815
1820
|
);
|
|
1816
1821
|
};
|
|
1817
1822
|
|
|
1823
|
+
const acsEndpointParamsSchema = z.object({
|
|
1824
|
+
providerId: z.string().optional(),
|
|
1825
|
+
});
|
|
1826
|
+
|
|
1827
|
+
const acsEndpointBodySchema = z.object({
|
|
1828
|
+
SAMLResponse: z.string(),
|
|
1829
|
+
RelayState: z.string().optional(),
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1818
1832
|
export const acsEndpoint = (options?: SSOOptions) => {
|
|
1819
1833
|
return createAuthEndpoint(
|
|
1820
1834
|
"/sso/saml2/sp/acs/:providerId",
|
|
1821
1835
|
{
|
|
1822
1836
|
method: "POST",
|
|
1823
|
-
params:
|
|
1824
|
-
|
|
1825
|
-
}),
|
|
1826
|
-
body: z.object({
|
|
1827
|
-
SAMLResponse: z.string(),
|
|
1828
|
-
RelayState: z.string().optional(),
|
|
1829
|
-
}),
|
|
1837
|
+
params: acsEndpointParamsSchema,
|
|
1838
|
+
body: acsEndpointBodySchema,
|
|
1830
1839
|
metadata: {
|
|
1831
1840
|
isAction: false,
|
|
1832
1841
|
allowedMediaTypes: [
|