fix deps, tsconfig, next-env-vars, zitadel api

This commit is contained in:
Max Peintner
2025-01-14 13:13:57 +01:00
parent c003ea2b22
commit 1736a2b3a0
8 changed files with 308 additions and 177 deletions

33
apps/login/next-env-vars.d.ts vendored Normal file
View File

@@ -0,0 +1,33 @@
declare namespace NodeJS {
interface ProcessEnv {
/**
* The system api url
*/
AUDIENCE: string;
/**
* The system api service user ID
*/
SYSTEM_USER_ID: string;
/**
* The service user key
*/
SYSTEM_USER_PRIVATE_KEY: string;
/**
* The instance url
*/
ZITADEL_API_URL: string;
/**
* The service user id for the instance
*/
ZITADEL_USER_ID: string;
/**
* The service user token for the instance
*/
ZITADEL_USER_TOKEN: string;
}
}

View File

@@ -44,14 +44,15 @@
"clsx": "1.2.1",
"copy-to-clipboard": "^3.3.3",
"deepmerge": "^4.3.1",
"jose": "^5.3.0",
"moment": "^2.29.4",
"next": "15.0.4-canary.23",
"next-intl": "^3.25.1",
"next-themes": "^0.2.1",
"nice-grpc": "2.0.1",
"qrcode.react": "^3.1.0",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.39.5",
"swr": "^2.2.0",
"tinycolor2": "1.4.2"
@@ -62,19 +63,20 @@
"@testing-library/react": "^16.0.1",
"@types/ms": "0.7.34",
"@types/node": "22.9.0",
"@types/react": "npm:types-react@19.0.0-rc.1",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
"@types/react": "19.0.2",
"@types/react-dom": "19.0.2",
"@types/tinycolor2": "1.4.3",
"@types/uuid": "^10.0.0",
"@vercel/git-hooks": "1.0.0",
"@zitadel/eslint-config": "workspace:*",
"@zitadel/prettier-config": "workspace:*",
"@zitadel/tailwind-config": "workspace:*",
"@zitadel/tsconfig": "workspace:*",
"autoprefixer": "10.4.20",
"concurrently": "^9.1.0",
"cypress": "^13.15.2",
"del-cli": "6.0.0",
"env-cmd": "^10.0.0",
"@zitadel/eslint-config": "workspace:*",
"grpc-tools": "1.12.4",
"jsdom": "^25.0.1",
"lint-staged": "15.2.10",
@@ -86,7 +88,6 @@
"start-server-and-test": "^2.0.8",
"tailwindcss": "3.4.14",
"ts-proto": "^2.2.7",
"typescript": "^5.6.3",
"@zitadel/tailwind-config": "workspace:*"
"typescript": "^5.6.3"
}
}

36
apps/login/src/lib/api.ts Normal file
View File

@@ -0,0 +1,36 @@
import { importPKCS8, SignJWT } from "jose";
import { getInstanceByHost } from "./zitadel";
export async function getInstanceUrl(host: string): Promise<string> {
const instance = await getInstanceByHost(host);
const generatedDomain = instance.domains.find(
(domain) => domain.generated === true,
);
if (!generatedDomain?.domain) {
throw new Error("No generated domain found");
}
console.log(`host: ${host}, api: ${generatedDomain?.domain}`);
return generatedDomain?.domain;
}
export async function systemAPIToken() {
const audience = process.env.AUDIENCE;
const userID = process.env.SYSTEM_USER_ID;
const key = process.env.SYSTEM_USER_PRIVATE_KEY;
const decodedToken = Buffer.from(key, "base64").toString("utf-8");
const token = new SignJWT({})
.setProtectedHeader({ alg: "RS256" })
.setIssuedAt()
.setExpirationTime("1h")
.setIssuer(userID)
.setSubject(userID)
.setAudience(audience)
.sign(await importPKCS8(decodedToken, "RS256"));
return token;
}

View File

@@ -1,32 +1,22 @@
import { create, createClientFor, Duration } from "@zitadel/client";
import { createServerTransport } from "@zitadel/client/node";
import {
createIdpServiceClient,
createOIDCServiceClient,
createOrganizationServiceClient,
createSessionServiceClient,
createSettingsServiceClient,
createUserServiceClient,
makeReqCtx,
} from "@zitadel/client/v2";
import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import {
AddHumanUserRequest,
ResendEmailCodeRequest,
ResendEmailCodeRequestSchema,
RetrieveIdentityProviderIntentRequest,
SendEmailCodeRequestSchema,
SetPasswordRequest,
SetPasswordRequestSchema,
VerifyPasskeyRegistrationRequest,
VerifyU2FRegistrationRequest,
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { create, Duration } from "@zitadel/client";
import { createSystemServiceClient } from "@zitadel/client/v1";
import { makeReqCtx } from "@zitadel/client/v2";
import { IdentityProviderService } from "@zitadel/proto/zitadel/idp/v2/idp_service_pb";
import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb";
import { CreateCallbackRequest } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
import {
CreateCallbackRequest,
OIDCService,
} from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
import { OrganizationService } from "@zitadel/proto/zitadel/org/v2/org_service_pb";
import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb";
import {
Checks,
SessionService,
} from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { SettingsService } from "@zitadel/proto/zitadel/settings/v2/settings_service_pb";
import { SendEmailVerificationCodeSchema } from "@zitadel/proto/zitadel/user/v2/email_pb";
import type { RedirectURLsJson } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import {
@@ -42,19 +32,20 @@ import {
User,
UserState,
} from "@zitadel/proto/zitadel/user/v2/user_pb";
import {
AddHumanUserRequest,
ResendEmailCodeRequest,
ResendEmailCodeRequestSchema,
RetrieveIdentityProviderIntentRequest,
SendEmailCodeRequestSchema,
SetPasswordRequest,
SetPasswordRequestSchema,
UserService,
VerifyPasskeyRegistrationRequest,
VerifyU2FRegistrationRequest,
} from "@zitadel/proto/zitadel/user/v2/user_service_pb";
import { unstable_cacheLife as cacheLife } from "next/cache";
const transport = createServerTransport(
process.env.ZITADEL_SERVICE_USER_TOKEN!,
{ baseUrl: process.env.ZITADEL_API_URL! },
);
export const sessionService = createSessionServiceClient(transport);
export const userService = createUserServiceClient(transport);
export const oidcService = createOIDCServiceClient(transport);
export const idpService = createIdpServiceClient(transport);
export const orgService = createOrganizationServiceClient(transport);
export const settingsService = createSettingsServiceClient(transport);
import { systemAPIToken } from "./api";
const useCache = process.env.DEBUG !== "true";
@@ -65,6 +56,86 @@ async function cacheWrapper<T>(callback: Promise<T>) {
return callback;
}
type ServiceClass =
| typeof IdentityProviderService
| typeof UserService
| typeof OrganizationService
| typeof SessionService
| typeof OIDCService
| typeof SettingsService;
async function createServiceForHost<T extends ServiceClass>(service: T) {
// const host = headers().get("X-Forwarded-Host");
// if (!host) {
// throw new Error("No host header found!");
// }
// let instanceUrl;
// try {
// instanceUrl = await getInstanceUrl(host);
// } catch (error) {
// console.error(
// "Could not get instance url, fallback to ZITADEL_API_URL",
// error,
// );
// instanceUrl = process.env.ZITADEL_API_URL;
// }
// remove in favor of the above
const instanceUrl = process.env.ZITADEL_API_URL;
const systemToken = await systemAPIToken();
const transport = createServerTransport(systemToken, {
baseUrl: instanceUrl,
});
return createClientFor<T>(service)(transport);
}
const idpService = await createServiceForHost(IdentityProviderService);
const orgService = await createServiceForHost(OrganizationService);
export const sessionService = await createServiceForHost(SessionService);
const userService = await createServiceForHost(UserService);
const oidcService = await createServiceForHost(OIDCService);
const settingsService = await createServiceForHost(SettingsService);
const systemService = async () => {
const systemToken = await systemAPIToken();
const transport = createServerTransport(systemToken, {
baseUrl: process.env.ZITADEL_API_URL,
});
return createSystemServiceClient(transport);
};
export async function getInstanceByHost(host: string) {
return (await systemService())
.listInstances(
{
queries: [
{
query: {
case: "domainQuery",
value: {
domains: [host],
},
},
},
],
},
{},
)
.then((resp) => {
if (resp.result.length !== 1) {
throw new Error("Could not find instance");
}
return resp.result[0];
});
}
export async function getBrandingSettings(organization?: string) {
const callback = settingsService
.getBrandingSettings({ ctx: makeReqCtx(organization) }, {})

View File

@@ -2,6 +2,7 @@
"extends": "@zitadel/tsconfig/nextjs.json",
"compilerOptions": {
"jsx": "preserve",
"target": "es2022",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]