@spfn/auth 0.2.0-beta.66 → 0.2.0-beta.67
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/LICENSE +1 -1
- package/README.md +37 -6
- package/dist/{authenticate-DKGNvSsH.d.ts → authenticate-Cn5krz5U.d.ts} +81 -9
- package/dist/config.d.ts +39 -3
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +16 -2
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +25 -8
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.d.ts +2 -2
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +59 -19
- package/dist/server.js +241 -31
- package/dist/server.js.map +1 -1
- package/dist/{session-2CyIVxMY.d.ts → session-s_hiXmXC.d.ts} +1 -1
- package/dist/{types-B4auHIax.d.ts → types-BtksCI9X.d.ts} +1 -1
- package/package.json +5 -4
package/dist/server.js
CHANGED
|
@@ -4501,7 +4501,7 @@ var init_types = __esm({
|
|
|
4501
4501
|
KEY_ALGORITHM = ["ES256", "RS256"];
|
|
4502
4502
|
INVITATION_STATUSES = ["pending", "accepted", "expired", "cancelled"];
|
|
4503
4503
|
USER_STATUSES = ["active", "inactive", "suspended"];
|
|
4504
|
-
SOCIAL_PROVIDERS = ["google", "github", "kakao", "naver", "superself"];
|
|
4504
|
+
SOCIAL_PROVIDERS = ["google", "apple", "github", "kakao", "naver", "superself"];
|
|
4505
4505
|
}
|
|
4506
4506
|
});
|
|
4507
4507
|
|
|
@@ -8104,8 +8104,8 @@ async function updateUserProfileService(userId, params) {
|
|
|
8104
8104
|
|
|
8105
8105
|
// src/server/services/oauth.service.ts
|
|
8106
8106
|
init_repositories();
|
|
8107
|
-
import { env as
|
|
8108
|
-
import { ValidationError as
|
|
8107
|
+
import { env as env11 } from "@spfn/auth/config";
|
|
8108
|
+
import { ValidationError as ValidationError5 } from "@spfn/core/errors";
|
|
8109
8109
|
|
|
8110
8110
|
// src/server/lib/oauth/google.ts
|
|
8111
8111
|
import { env as env7 } from "@spfn/auth/config";
|
|
@@ -8255,7 +8255,59 @@ function getRegisteredProviders() {
|
|
|
8255
8255
|
return [...registry.values()];
|
|
8256
8256
|
}
|
|
8257
8257
|
|
|
8258
|
+
// src/server/lib/oauth/jwks-verify.ts
|
|
8259
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
8260
|
+
import { InvalidSocialTokenError } from "@spfn/auth/errors";
|
|
8261
|
+
var CLOCK_TOLERANCE_SECONDS = 30;
|
|
8262
|
+
var jwksByUri = /* @__PURE__ */ new Map();
|
|
8263
|
+
function getRemoteJwks(jwksUri) {
|
|
8264
|
+
const cached = jwksByUri.get(jwksUri);
|
|
8265
|
+
if (cached) {
|
|
8266
|
+
return cached;
|
|
8267
|
+
}
|
|
8268
|
+
const jwks = createRemoteJWKSet(new URL(jwksUri));
|
|
8269
|
+
jwksByUri.set(jwksUri, jwks);
|
|
8270
|
+
return jwks;
|
|
8271
|
+
}
|
|
8272
|
+
async function verifyIdToken(params) {
|
|
8273
|
+
const payload = await verifySignature(params);
|
|
8274
|
+
if (payload.nonce !== params.expectedNonce) {
|
|
8275
|
+
throw new InvalidSocialTokenError({ message: "id_token nonce mismatch" });
|
|
8276
|
+
}
|
|
8277
|
+
if (typeof payload.sub !== "string" || payload.sub.length === 0) {
|
|
8278
|
+
throw new InvalidSocialTokenError({ message: "id_token is missing the subject (sub) claim" });
|
|
8279
|
+
}
|
|
8280
|
+
return payload;
|
|
8281
|
+
}
|
|
8282
|
+
async function verifySignature(params) {
|
|
8283
|
+
try {
|
|
8284
|
+
const { payload } = await jwtVerify(params.idToken, getRemoteJwks(params.jwksUri), {
|
|
8285
|
+
issuer: params.issuer,
|
|
8286
|
+
audience: params.audiences,
|
|
8287
|
+
algorithms: params.algorithms,
|
|
8288
|
+
clockTolerance: CLOCK_TOLERANCE_SECONDS
|
|
8289
|
+
});
|
|
8290
|
+
return payload;
|
|
8291
|
+
} catch (err) {
|
|
8292
|
+
authLogger.service.warn("id_token signature/claims verification failed", {
|
|
8293
|
+
reason: err instanceof Error ? err.message : "unknown"
|
|
8294
|
+
});
|
|
8295
|
+
throw new InvalidSocialTokenError();
|
|
8296
|
+
}
|
|
8297
|
+
}
|
|
8298
|
+
|
|
8258
8299
|
// src/server/lib/oauth/google-provider.ts
|
|
8300
|
+
import { env as env9 } from "@spfn/auth/config";
|
|
8301
|
+
import { ValidationError as ValidationError3 } from "@spfn/core/errors";
|
|
8302
|
+
var GOOGLE_JWKS_URI = "https://www.googleapis.com/oauth2/v3/certs";
|
|
8303
|
+
var GOOGLE_ISSUERS = ["https://accounts.google.com", "accounts.google.com"];
|
|
8304
|
+
function getGoogleNativeAudiences() {
|
|
8305
|
+
const ids = (env9.SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
8306
|
+
if (env9.SPFN_AUTH_GOOGLE_CLIENT_ID) {
|
|
8307
|
+
ids.push(env9.SPFN_AUTH_GOOGLE_CLIENT_ID);
|
|
8308
|
+
}
|
|
8309
|
+
return ids;
|
|
8310
|
+
}
|
|
8259
8311
|
var googleProvider = {
|
|
8260
8312
|
id: "google",
|
|
8261
8313
|
isEnabled: isGoogleOAuthEnabled,
|
|
@@ -8285,20 +8337,98 @@ var googleProvider = {
|
|
|
8285
8337
|
refreshToken: tokens.refresh_token,
|
|
8286
8338
|
expiresIn: tokens.expires_in
|
|
8287
8339
|
};
|
|
8340
|
+
},
|
|
8341
|
+
async verifyNativeIdToken(idToken, options) {
|
|
8342
|
+
const audiences = getGoogleNativeAudiences();
|
|
8343
|
+
if (audiences.length === 0) {
|
|
8344
|
+
throw new ValidationError3({
|
|
8345
|
+
message: "Google native sign-in is not configured. Set SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS."
|
|
8346
|
+
});
|
|
8347
|
+
}
|
|
8348
|
+
const payload = await verifyIdToken({
|
|
8349
|
+
idToken,
|
|
8350
|
+
jwksUri: GOOGLE_JWKS_URI,
|
|
8351
|
+
issuer: GOOGLE_ISSUERS,
|
|
8352
|
+
audiences,
|
|
8353
|
+
algorithms: ["RS256"],
|
|
8354
|
+
expectedNonce: options.nonce
|
|
8355
|
+
});
|
|
8356
|
+
return {
|
|
8357
|
+
providerUserId: payload.sub,
|
|
8358
|
+
email: payload.email ?? null,
|
|
8359
|
+
emailVerified: payload.email_verified === true || payload.email_verified === "true",
|
|
8360
|
+
name: payload.name,
|
|
8361
|
+
avatar: payload.picture
|
|
8362
|
+
};
|
|
8288
8363
|
}
|
|
8289
8364
|
};
|
|
8290
8365
|
registerOAuthProvider(googleProvider);
|
|
8291
8366
|
|
|
8367
|
+
// src/server/lib/oauth/apple-provider.ts
|
|
8368
|
+
import { createHash as createHash2 } from "crypto";
|
|
8369
|
+
import { env as env10 } from "@spfn/auth/config";
|
|
8370
|
+
import { ValidationError as ValidationError4 } from "@spfn/core/errors";
|
|
8371
|
+
var APPLE_JWKS_URI = "https://appleid.apple.com/auth/keys";
|
|
8372
|
+
var APPLE_ISSUER = "https://appleid.apple.com";
|
|
8373
|
+
function getAppleClientIds() {
|
|
8374
|
+
return (env10.SPFN_AUTH_APPLE_CLIENT_IDS || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
8375
|
+
}
|
|
8376
|
+
function hashNonce(rawNonce) {
|
|
8377
|
+
return createHash2("sha256").update(rawNonce).digest("hex");
|
|
8378
|
+
}
|
|
8379
|
+
function unsupportedWebFlow() {
|
|
8380
|
+
throw new ValidationError4({
|
|
8381
|
+
message: "Apple provider supports native id_token sign-in only. Use POST /_auth/oauth/apple/native."
|
|
8382
|
+
});
|
|
8383
|
+
}
|
|
8384
|
+
var appleProvider = {
|
|
8385
|
+
id: "apple",
|
|
8386
|
+
isEnabled() {
|
|
8387
|
+
return getAppleClientIds().length > 0;
|
|
8388
|
+
},
|
|
8389
|
+
getAuthUrl() {
|
|
8390
|
+
unsupportedWebFlow();
|
|
8391
|
+
},
|
|
8392
|
+
async exchangeCodeForTokens() {
|
|
8393
|
+
unsupportedWebFlow();
|
|
8394
|
+
},
|
|
8395
|
+
async getUserInfo() {
|
|
8396
|
+
unsupportedWebFlow();
|
|
8397
|
+
},
|
|
8398
|
+
async verifyNativeIdToken(idToken, options) {
|
|
8399
|
+
const audiences = getAppleClientIds();
|
|
8400
|
+
if (audiences.length === 0) {
|
|
8401
|
+
throw new ValidationError4({
|
|
8402
|
+
message: "Apple native sign-in is not configured. Set SPFN_AUTH_APPLE_CLIENT_IDS."
|
|
8403
|
+
});
|
|
8404
|
+
}
|
|
8405
|
+
const payload = await verifyIdToken({
|
|
8406
|
+
idToken,
|
|
8407
|
+
jwksUri: APPLE_JWKS_URI,
|
|
8408
|
+
issuer: APPLE_ISSUER,
|
|
8409
|
+
audiences,
|
|
8410
|
+
algorithms: ["RS256"],
|
|
8411
|
+
expectedNonce: hashNonce(options.nonce)
|
|
8412
|
+
});
|
|
8413
|
+
return {
|
|
8414
|
+
providerUserId: payload.sub,
|
|
8415
|
+
email: payload.email ?? null,
|
|
8416
|
+
emailVerified: payload.email_verified === true || payload.email_verified === "true"
|
|
8417
|
+
};
|
|
8418
|
+
}
|
|
8419
|
+
};
|
|
8420
|
+
registerOAuthProvider(appleProvider);
|
|
8421
|
+
|
|
8292
8422
|
// src/server/services/oauth.service.ts
|
|
8293
8423
|
function requireEnabledProvider(provider) {
|
|
8294
8424
|
const oauthProvider = getOAuthProvider(provider);
|
|
8295
8425
|
if (!oauthProvider) {
|
|
8296
|
-
throw new
|
|
8426
|
+
throw new ValidationError5({
|
|
8297
8427
|
message: `Unsupported OAuth provider: ${provider}. No provider is registered for this id.`
|
|
8298
8428
|
});
|
|
8299
8429
|
}
|
|
8300
8430
|
if (!oauthProvider.isEnabled()) {
|
|
8301
|
-
throw new
|
|
8431
|
+
throw new ValidationError5({
|
|
8302
8432
|
message: `OAuth provider '${provider}' is registered but not configured. Check its required environment variables.`
|
|
8303
8433
|
});
|
|
8304
8434
|
}
|
|
@@ -8306,7 +8436,7 @@ function requireEnabledProvider(provider) {
|
|
|
8306
8436
|
}
|
|
8307
8437
|
function tokenExpiryDate(expiresIn) {
|
|
8308
8438
|
if (!Number.isFinite(expiresIn)) {
|
|
8309
|
-
throw new
|
|
8439
|
+
throw new ValidationError5({
|
|
8310
8440
|
message: `Invalid token expiry returned from OAuth provider: ${expiresIn}`
|
|
8311
8441
|
});
|
|
8312
8442
|
}
|
|
@@ -8330,7 +8460,7 @@ async function oauthCallbackService(params) {
|
|
|
8330
8460
|
const { provider, code, state } = params;
|
|
8331
8461
|
const stateData = await verifyOAuthState(state);
|
|
8332
8462
|
if (stateData.provider !== provider) {
|
|
8333
|
-
throw new
|
|
8463
|
+
throw new ValidationError5({
|
|
8334
8464
|
message: "OAuth state provider mismatch"
|
|
8335
8465
|
});
|
|
8336
8466
|
}
|
|
@@ -8363,8 +8493,8 @@ async function oauthCallbackService(params) {
|
|
|
8363
8493
|
algorithm: stateData.algorithm
|
|
8364
8494
|
});
|
|
8365
8495
|
await updateLastLoginService(userId);
|
|
8366
|
-
const appUrl =
|
|
8367
|
-
const callbackPath =
|
|
8496
|
+
const appUrl = env11.NEXT_PUBLIC_SPFN_APP_URL || env11.SPFN_APP_URL;
|
|
8497
|
+
const callbackPath = env11.SPFN_AUTH_OAUTH_SUCCESS_URL || "/auth/callback";
|
|
8368
8498
|
const callbackUrl = callbackPath.startsWith("http") ? callbackPath : `${appUrl}${callbackPath}`;
|
|
8369
8499
|
const redirectUrl = buildRedirectUrl(callbackUrl, {
|
|
8370
8500
|
userId: String(userId),
|
|
@@ -8398,7 +8528,7 @@ async function createOrLinkUser(provider, identity, tokens) {
|
|
|
8398
8528
|
let isNewUser = false;
|
|
8399
8529
|
if (existingUser) {
|
|
8400
8530
|
if (!identity.emailVerified) {
|
|
8401
|
-
throw new
|
|
8531
|
+
throw new ValidationError5({
|
|
8402
8532
|
message: "Cannot link to existing account with unverified email. Please verify your email with the provider first."
|
|
8403
8533
|
});
|
|
8404
8534
|
}
|
|
@@ -8432,9 +8562,9 @@ async function createOrLinkUser(provider, identity, tokens) {
|
|
|
8432
8562
|
provider,
|
|
8433
8563
|
providerUserId: identity.providerUserId,
|
|
8434
8564
|
providerEmail: identity.email,
|
|
8435
|
-
accessToken: tokens
|
|
8436
|
-
refreshToken: tokens
|
|
8437
|
-
tokenExpiresAt: tokenExpiryDate(tokens.expiresIn)
|
|
8565
|
+
accessToken: tokens?.accessToken ?? null,
|
|
8566
|
+
refreshToken: tokens?.refreshToken ?? null,
|
|
8567
|
+
tokenExpiresAt: tokens ? tokenExpiryDate(tokens.expiresIn) : null
|
|
8438
8568
|
});
|
|
8439
8569
|
return { userId, isNewUser };
|
|
8440
8570
|
}
|
|
@@ -8449,7 +8579,7 @@ function buildRedirectUrl(baseUrl, params) {
|
|
|
8449
8579
|
return `${url.pathname}${url.search}`;
|
|
8450
8580
|
}
|
|
8451
8581
|
function buildOAuthErrorUrl(error) {
|
|
8452
|
-
const errorUrl =
|
|
8582
|
+
const errorUrl = env11.SPFN_AUTH_OAUTH_ERROR_URL || "/auth/error?error={error}";
|
|
8453
8583
|
return errorUrl.replace("{error}", encodeURIComponent(error));
|
|
8454
8584
|
}
|
|
8455
8585
|
function isOAuthProviderEnabled(provider) {
|
|
@@ -8462,7 +8592,7 @@ var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
|
|
|
8462
8592
|
async function getGoogleAccessToken(userId) {
|
|
8463
8593
|
const account = await socialAccountsRepository.findByUserIdAndProvider(userId, "google");
|
|
8464
8594
|
if (!account) {
|
|
8465
|
-
throw new
|
|
8595
|
+
throw new ValidationError5({
|
|
8466
8596
|
message: "No Google account linked. User must sign in with Google first."
|
|
8467
8597
|
});
|
|
8468
8598
|
}
|
|
@@ -8471,7 +8601,7 @@ async function getGoogleAccessToken(userId) {
|
|
|
8471
8601
|
return account.accessToken;
|
|
8472
8602
|
}
|
|
8473
8603
|
if (!account.refreshToken) {
|
|
8474
|
-
throw new
|
|
8604
|
+
throw new ValidationError5({
|
|
8475
8605
|
message: "Google refresh token not available. User must re-authenticate with Google."
|
|
8476
8606
|
});
|
|
8477
8607
|
}
|
|
@@ -8484,6 +8614,57 @@ async function getGoogleAccessToken(userId) {
|
|
|
8484
8614
|
return tokens.access_token;
|
|
8485
8615
|
}
|
|
8486
8616
|
|
|
8617
|
+
// src/server/services/oauth-native.service.ts
|
|
8618
|
+
init_repositories();
|
|
8619
|
+
import { ValidationError as ValidationError6 } from "@spfn/core/errors";
|
|
8620
|
+
import { runInTransaction, onAfterCommit } from "@spfn/core/db";
|
|
8621
|
+
async function oauthNativeService(params) {
|
|
8622
|
+
const oauthProvider = getOAuthProvider(params.provider);
|
|
8623
|
+
if (!oauthProvider?.verifyNativeIdToken) {
|
|
8624
|
+
throw new ValidationError6({
|
|
8625
|
+
message: `Provider '${params.provider}' does not support native id_token sign-in.`
|
|
8626
|
+
});
|
|
8627
|
+
}
|
|
8628
|
+
const identity = await oauthProvider.verifyNativeIdToken(params.idToken, { nonce: params.nonce });
|
|
8629
|
+
if (params.profile?.name && !identity.name) {
|
|
8630
|
+
identity.name = params.profile.name;
|
|
8631
|
+
}
|
|
8632
|
+
return persistNativeLogin(identity, params);
|
|
8633
|
+
}
|
|
8634
|
+
async function persistNativeLogin(identity, params) {
|
|
8635
|
+
return runInTransaction(async () => {
|
|
8636
|
+
const existing = await socialAccountsRepository.findByProviderAndProviderId(
|
|
8637
|
+
params.provider,
|
|
8638
|
+
identity.providerUserId
|
|
8639
|
+
);
|
|
8640
|
+
let userId;
|
|
8641
|
+
let isNewUser = false;
|
|
8642
|
+
if (existing) {
|
|
8643
|
+
userId = existing.userId;
|
|
8644
|
+
} else {
|
|
8645
|
+
const result = await createOrLinkUser(params.provider, identity);
|
|
8646
|
+
userId = result.userId;
|
|
8647
|
+
isNewUser = result.isNewUser;
|
|
8648
|
+
}
|
|
8649
|
+
await registerPublicKeyService({
|
|
8650
|
+
userId,
|
|
8651
|
+
keyId: params.keyId,
|
|
8652
|
+
publicKey: params.publicKey,
|
|
8653
|
+
fingerprint: params.fingerprint,
|
|
8654
|
+
algorithm: params.algorithm
|
|
8655
|
+
});
|
|
8656
|
+
await updateLastLoginService(userId);
|
|
8657
|
+
const eventPayload = {
|
|
8658
|
+
userId: String(userId),
|
|
8659
|
+
provider: params.provider,
|
|
8660
|
+
email: identity.email || void 0,
|
|
8661
|
+
metadata: params.metadata
|
|
8662
|
+
};
|
|
8663
|
+
onAfterCommit(() => (isNewUser ? authRegisterEvent : authLoginEvent).emit(eventPayload));
|
|
8664
|
+
return { userId: String(userId), keyId: params.keyId, isNewUser };
|
|
8665
|
+
}, { context: "auth:oauth-native" });
|
|
8666
|
+
}
|
|
8667
|
+
|
|
8487
8668
|
// src/server/routes/auth/index.ts
|
|
8488
8669
|
init_esm();
|
|
8489
8670
|
import { Transactional } from "@spfn/core/db";
|
|
@@ -9239,7 +9420,7 @@ var userRouter = defineRouter3({
|
|
|
9239
9420
|
init_esm();
|
|
9240
9421
|
init_types();
|
|
9241
9422
|
import { Transactional as Transactional2 } from "@spfn/core/db";
|
|
9242
|
-
import { ValidationError as
|
|
9423
|
+
import { ValidationError as ValidationError7 } from "@spfn/core/errors";
|
|
9243
9424
|
import { defineRouter as defineRouter4, route as route4 } from "@spfn/core/route";
|
|
9244
9425
|
var providerParams = Type.Object({
|
|
9245
9426
|
provider: Type.Union(SOCIAL_PROVIDERS.map((p) => Type.Literal(p)), {
|
|
@@ -9342,10 +9523,10 @@ var getGoogleOAuthUrl = route4.post("/_auth/oauth/google/url").input({
|
|
|
9342
9523
|
}).skip(["auth"]).handler(async (c) => {
|
|
9343
9524
|
const { body } = await c.data();
|
|
9344
9525
|
if (!isGoogleOAuthEnabled()) {
|
|
9345
|
-
throw new
|
|
9526
|
+
throw new ValidationError7({ message: "Google OAuth is not configured" });
|
|
9346
9527
|
}
|
|
9347
9528
|
if (!body.state) {
|
|
9348
|
-
throw new
|
|
9529
|
+
throw new ValidationError7({
|
|
9349
9530
|
message: "OAuth state is required. Ensure the OAuth interceptor is configured."
|
|
9350
9531
|
});
|
|
9351
9532
|
}
|
|
@@ -9432,12 +9613,36 @@ var getProviderOAuthUrl = route4.post("/_auth/oauth/:provider/url").input({
|
|
|
9432
9613
|
const { params, body } = await c.data();
|
|
9433
9614
|
const provider = requireEnabledProvider(params.provider);
|
|
9434
9615
|
if (!body.state) {
|
|
9435
|
-
throw new
|
|
9616
|
+
throw new ValidationError7({
|
|
9436
9617
|
message: "OAuth state is required. Ensure the OAuth interceptor is configured."
|
|
9437
9618
|
});
|
|
9438
9619
|
}
|
|
9439
9620
|
return { authUrl: provider.getAuthUrl(body.state) };
|
|
9440
9621
|
});
|
|
9622
|
+
var oauthNative = route4.post("/_auth/oauth/:provider/native").input({
|
|
9623
|
+
params: providerParams,
|
|
9624
|
+
body: Type.Object({
|
|
9625
|
+
idToken: Type.String({ description: "id_token from native/web social SDK" }),
|
|
9626
|
+
nonce: Type.String({ description: "Raw nonce used when requesting the id_token" }),
|
|
9627
|
+
publicKey: Type.String({ description: "Client public key (Base64 DER)" }),
|
|
9628
|
+
keyId: Type.String({ description: "Key identifier (UUID)" }),
|
|
9629
|
+
fingerprint: Type.String({ description: "Key fingerprint (SHA-256 hex)" }),
|
|
9630
|
+
algorithm: Type.Union(KEY_ALGORITHM.map((a) => Type.Literal(a)), {
|
|
9631
|
+
description: "Key algorithm (ES256 or RS256)"
|
|
9632
|
+
}),
|
|
9633
|
+
profile: Type.Optional(Type.Object({
|
|
9634
|
+
name: Type.Optional(Type.String())
|
|
9635
|
+
}, {
|
|
9636
|
+
description: "Optional profile. Apple provides name only on first sign-in."
|
|
9637
|
+
})),
|
|
9638
|
+
metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
9639
|
+
description: "Custom metadata passed to auth events (e.g. referral code, UTM params)"
|
|
9640
|
+
}))
|
|
9641
|
+
})
|
|
9642
|
+
}).skip(["auth"]).handler(async (c) => {
|
|
9643
|
+
const { params, body } = await c.data();
|
|
9644
|
+
return await oauthNativeService({ provider: params.provider, ...body });
|
|
9645
|
+
});
|
|
9441
9646
|
var oauthRouter = defineRouter4({
|
|
9442
9647
|
oauthGoogleStart,
|
|
9443
9648
|
oauthGoogleCallback,
|
|
@@ -9447,7 +9652,8 @@ var oauthRouter = defineRouter4({
|
|
|
9447
9652
|
oauthFinalize,
|
|
9448
9653
|
oauthProviderStart,
|
|
9449
9654
|
oauthProviderCallback,
|
|
9450
|
-
getProviderOAuthUrl
|
|
9655
|
+
getProviderOAuthUrl,
|
|
9656
|
+
oauthNative
|
|
9451
9657
|
});
|
|
9452
9658
|
|
|
9453
9659
|
// src/server/routes/admin/index.ts
|
|
@@ -9570,6 +9776,7 @@ var mainAuthRouter = defineRouter5({
|
|
|
9570
9776
|
oauthProviderStart,
|
|
9571
9777
|
oauthProviderCallback,
|
|
9572
9778
|
getProviderOAuthUrl,
|
|
9779
|
+
oauthNative,
|
|
9573
9780
|
// Invitation routes
|
|
9574
9781
|
getInvitation,
|
|
9575
9782
|
acceptInvitation: acceptInvitation2,
|
|
@@ -9700,10 +9907,10 @@ function shouldRotateKey(createdAt, rotationDays = 90) {
|
|
|
9700
9907
|
|
|
9701
9908
|
// src/server/lib/session.ts
|
|
9702
9909
|
import * as jose2 from "jose";
|
|
9703
|
-
import { env as
|
|
9910
|
+
import { env as env12 } from "@spfn/auth/config";
|
|
9704
9911
|
import { env as coreEnv } from "@spfn/core/config";
|
|
9705
9912
|
async function getSessionSecretKey() {
|
|
9706
|
-
const secret =
|
|
9913
|
+
const secret = env12.SPFN_AUTH_SESSION_SECRET;
|
|
9707
9914
|
const encoder = new TextEncoder();
|
|
9708
9915
|
const data = encoder.encode(secret);
|
|
9709
9916
|
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
@@ -9785,14 +9992,14 @@ async function shouldRefreshSession(jwt4, thresholdHours = 24) {
|
|
|
9785
9992
|
}
|
|
9786
9993
|
|
|
9787
9994
|
// src/server/setup.ts
|
|
9788
|
-
import { env as
|
|
9995
|
+
import { env as env13 } from "@spfn/auth/config";
|
|
9789
9996
|
import { getRoleByName as getRoleByName2 } from "@spfn/auth/server";
|
|
9790
9997
|
init_repositories();
|
|
9791
9998
|
function parseAdminAccounts() {
|
|
9792
9999
|
const accounts = [];
|
|
9793
|
-
if (
|
|
10000
|
+
if (env13.SPFN_AUTH_ADMIN_ACCOUNTS) {
|
|
9794
10001
|
try {
|
|
9795
|
-
const accountsJson =
|
|
10002
|
+
const accountsJson = env13.SPFN_AUTH_ADMIN_ACCOUNTS;
|
|
9796
10003
|
const parsed = JSON.parse(accountsJson);
|
|
9797
10004
|
if (!Array.isArray(parsed)) {
|
|
9798
10005
|
authLogger.setup.error("\u274C SPFN_AUTH_ADMIN_ACCOUNTS must be an array");
|
|
@@ -9819,11 +10026,11 @@ function parseAdminAccounts() {
|
|
|
9819
10026
|
return accounts;
|
|
9820
10027
|
}
|
|
9821
10028
|
}
|
|
9822
|
-
const adminEmails =
|
|
10029
|
+
const adminEmails = env13.SPFN_AUTH_ADMIN_EMAILS;
|
|
9823
10030
|
if (adminEmails) {
|
|
9824
10031
|
const emails = adminEmails.split(",").map((s) => s.trim());
|
|
9825
|
-
const passwords = (
|
|
9826
|
-
const roles2 = (
|
|
10032
|
+
const passwords = (env13.SPFN_AUTH_ADMIN_PASSWORDS || "").split(",").map((s) => s.trim());
|
|
10033
|
+
const roles2 = (env13.SPFN_AUTH_ADMIN_ROLES || "").split(",").map((s) => s.trim());
|
|
9827
10034
|
if (passwords.length !== emails.length) {
|
|
9828
10035
|
authLogger.setup.error("\u274C SPFN_AUTH_ADMIN_EMAILS and SPFN_AUTH_ADMIN_PASSWORDS length mismatch");
|
|
9829
10036
|
return accounts;
|
|
@@ -9845,8 +10052,8 @@ function parseAdminAccounts() {
|
|
|
9845
10052
|
}
|
|
9846
10053
|
return accounts;
|
|
9847
10054
|
}
|
|
9848
|
-
const adminEmail =
|
|
9849
|
-
const adminPassword =
|
|
10055
|
+
const adminEmail = env13.SPFN_AUTH_ADMIN_EMAIL;
|
|
10056
|
+
const adminPassword = env13.SPFN_AUTH_ADMIN_PASSWORD;
|
|
9850
10057
|
if (adminEmail && adminPassword) {
|
|
9851
10058
|
accounts.push({
|
|
9852
10059
|
email: adminEmail,
|
|
@@ -9952,6 +10159,7 @@ export {
|
|
|
9952
10159
|
VerificationPurposeSchema,
|
|
9953
10160
|
acceptInvitation,
|
|
9954
10161
|
addPermissionToRole,
|
|
10162
|
+
appleProvider,
|
|
9955
10163
|
authLogger,
|
|
9956
10164
|
authLoginEvent,
|
|
9957
10165
|
authMetadata,
|
|
@@ -10031,6 +10239,7 @@ export {
|
|
|
10031
10239
|
loginService,
|
|
10032
10240
|
logoutService,
|
|
10033
10241
|
oauthCallbackService,
|
|
10242
|
+
oauthNativeService,
|
|
10034
10243
|
oauthStartService,
|
|
10035
10244
|
oneTimeTokenAuth,
|
|
10036
10245
|
optionalAuth,
|
|
@@ -10082,6 +10291,7 @@ export {
|
|
|
10082
10291
|
verificationCodesRepository,
|
|
10083
10292
|
verifyClientToken,
|
|
10084
10293
|
verifyCodeService,
|
|
10294
|
+
verifyIdToken,
|
|
10085
10295
|
verifyKeyFingerprint,
|
|
10086
10296
|
verifyOAuthState,
|
|
10087
10297
|
verifyOneTimeTokenService,
|