Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: default redirect, server redirects, nextjs 15 #255

Merged
merged 31 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
050ef34
session item rehaul, finish session util
peintnermax Oct 30, 2024
c124100
redirects
peintnermax Oct 30, 2024
72f35d9
Merge branch 'main' into default-redirect
peintnermax Nov 14, 2024
98391c1
cleanup
peintnermax Nov 18, 2024
2fd7cf0
Merge branch 'main' into default-redirect
peintnermax Nov 18, 2024
5db61c8
idp cleanup
peintnermax Nov 18, 2024
fd90fcb
format
peintnermax Nov 18, 2024
56f2b90
finish flow
peintnermax Nov 18, 2024
dcee01d
cleanup register, check for allowed methods
peintnermax Nov 19, 2024
2c542b8
cleanup pwd continue
peintnermax Nov 19, 2024
f187ddc
Merge branch 'main' into default-redirect
peintnermax Nov 21, 2024
ea95a20
cleanup utils
peintnermax Nov 21, 2024
21cd5e7
initial stub for loginsettings
peintnermax Nov 21, 2024
68f7ea5
cleanup register
peintnermax Nov 21, 2024
7e1445d
stub to allow register
peintnermax Nov 21, 2024
b1f6257
remove nextstep on pwd pages
peintnermax Nov 21, 2024
5931c56
boolean
peintnermax Nov 21, 2024
de78789
auth method change
peintnermax Nov 21, 2024
61bb6ac
change test ids
peintnermax Nov 22, 2024
ff73d8e
use before stub
peintnermax Nov 22, 2024
19c310f
remove type check
peintnermax Nov 22, 2024
837cd4f
update nextjs to 15
peintnermax Nov 22, 2024
fe615a2
lint
peintnermax Nov 22, 2024
ee993af
babel
peintnermax Nov 22, 2024
2cb7267
canary version
peintnermax Nov 22, 2024
58dbcdc
rm cache life in layout
peintnermax Nov 22, 2024
7796f59
add suspense
peintnermax Nov 22, 2024
e964c7c
rm caching of i18n
peintnermax Nov 25, 2024
b48c25f
lint
peintnermax Nov 25, 2024
76e9fea
scss, module, nextjs, hydration fixes
peintnermax Nov 25, 2024
74eae3a
only cache in prod
peintnermax Nov 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions acceptance/tests/register-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ const passwordConfirmField = "password-confirm-text-input";

export async function registerUserScreenPassword(page: Page, firstname: string, lastname: string, email: string) {
await registerUserScreen(page, firstname, lastname, email);
await page.getByTestId("Password-radio").click();
await page.getByTestId("password-radio").click();
}

export async function registerUserScreenPasskey(page: Page, firstname: string, lastname: string, email: string) {
await registerUserScreen(page, firstname, lastname, email);
await page.getByTestId("Passkeys-radio").click();
await page.getByTestId("passkey-radio").click();
}

export async function registerPasswordScreen(page: Page, password1: string, password2: string) {
Expand Down
18 changes: 15 additions & 3 deletions apps/login/cypress/integration/register.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ describe("register", () => {
result: [{ id: "256088834543534543" }],
},
});
stub("zitadel.settings.v2.SettingsService", "GetLoginSettings", {
data: {
settings: {
passkeysType: 1,
allowRegister: true,
allowUsernamePassword: true,
defaultRedirectUri: "",
},
},
});
stub("zitadel.user.v2.UserService", "AddHumanUser", {
data: {
userId: "221394658884845598",
Expand Down Expand Up @@ -53,9 +63,11 @@ describe("register", () => {

it("should redirect a user who selects passwordless on register to /passkey/set", () => {
cy.visit("/register");
cy.get('input[autocomplete="firstname"]').focus().type("John");
cy.get('input[autocomplete="lastname"]').focus().type("Doe");
cy.get('input[autocomplete="email"]').focus().type("[email protected]");
cy.get('input[data-testid="firstname-text-input"]').focus().type("John");
cy.get('input[data-testid="lastname-text-input"]').focus().type("Doe");
cy.get('input[data-testid="email-text-input"]')
.focus()
.type("[email protected]");
cy.get('input[type="checkbox"][value="privacypolicy"]').check();
cy.get('input[type="checkbox"][value="tos"]').check();
cy.get('button[type="submit"]').click();
Expand Down
15 changes: 14 additions & 1 deletion apps/login/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@
}
},
"register": {
"methods": {
"passkey": "Passkey",
"password": "Password"
},
"disabled": {
"title": "Registrierung deaktiviert",
"description": "Die Registrierung ist deaktiviert. Bitte wenden Sie sich an den Administrator."
},
"missingdata": {
"title": "Registrierung fehlgeschlagen",
"description": "Einige Daten fehlen. Bitte überprüfen Sie Ihre Eingaben."
},
"title": "Registrieren",
"description": "Erstellen Sie Ihr ZITADEL-Konto.",
"selectMethod": "Wählen Sie die Methode, mit der Sie sich authentifizieren möchten",
Expand Down Expand Up @@ -151,7 +163,8 @@
},
"signedin": {
"title": "Willkommen {user}!",
"description": "Sie sind angemeldet."
"description": "Sie sind angemeldet.",
"continue": "Weiter"
},
"verify": {
"userIdMissing": "Keine Benutzer-ID angegeben!",
Expand Down
15 changes: 14 additions & 1 deletion apps/login/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@
}
},
"register": {
"methods": {
"passkey": "Passkey",
"password": "Password"
},
"disabled": {
"title": "Registration disabled",
"description": "The registration is disabled. Please contact your administrator."
},
"missingdata": {
"title": "Missing data",
"description": "Provide email, first and last name to register."
},
"title": "Register",
"description": "Create your ZITADEL account.",
"selectMethod": "Select the method you would like to authenticate",
Expand Down Expand Up @@ -151,7 +163,8 @@
},
"signedin": {
"title": "Welcome {user}!",
"description": "You are signed in."
"description": "You are signed in.",
"continue": "Continue"
},
"verify": {
"userIdMissing": "No userId provided!",
Expand Down
15 changes: 14 additions & 1 deletion apps/login/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@
}
},
"register": {
"methods": {
"passkey": "Clave de acceso",
"password": "Contraseña"
},
"disabled": {
"title": "Registro deshabilitado",
"description": "Registrarse está deshabilitado en este momento."
},
"missingdata": {
"title": "Datos faltantes",
"description": "No se proporcionaron datos suficientes para el registro."
},
"title": "Registrarse",
"description": "Crea tu cuenta ZITADEL.",
"selectMethod": "Selecciona el método con el que deseas autenticarte",
Expand Down Expand Up @@ -151,7 +163,8 @@
},
"signedin": {
"title": "¡Bienvenido {user}!",
"description": "Has iniciado sesión."
"description": "Has iniciado sesión.",
"continue": "Continuar"
},
"verify": {
"userIdMissing": "¡No se proporcionó userId!",
Expand Down
15 changes: 14 additions & 1 deletion apps/login/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@
}
},
"register": {
"methods": {
"passkey": "Passkey",
"password": "Password"
},
"disabled": {
"title": "Registration disabled",
"description": "Registrazione disabilitata. Contatta l'amministratore di sistema per assistenza."
},
"missingdata": {
"title": "Registrazione",
"description": "Inserisci i tuoi dati per registrarti."
},
"title": "Registrati",
"description": "Crea il tuo account ZITADEL.",
"selectMethod": "Seleziona il metodo con cui desideri autenticarti",
Expand Down Expand Up @@ -151,7 +163,8 @@
},
"signedin": {
"title": "Benvenuto {user}!",
"description": "Sei connesso."
"description": "Sei connesso.",
"continue": "Continua"
},
"verify": {
"userIdMissing": "Nessun userId fornito!",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
{
"service": "zitadel.settings.v2.SettingsService",
"method": "GetBrandingSettings",
"out": {}
"out": {
"data": {
"settings": {
"darkTheme": {
"backgroundColor": "#ff0000"
}
}
}
}
},
{
"service": "zitadel.settings.v2.SettingsService",
Expand Down
2 changes: 1 addition & 1 deletion apps/login/next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
4 changes: 3 additions & 1 deletion apps/login/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ const secureHeaders = [

const nextConfig = {
reactStrictMode: true, // Recommended for the `pages` directory, default in `app`.
swcMinify: true,
experimental: {
dynamicIO: true,
},
images: {
remotePatterns: [
{
Expand Down
14 changes: 7 additions & 7 deletions apps/login/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"type": "module",
"scripts": {
"dev": "next dev",
"dev": "next dev --turbopack",
"test": "concurrently --timings --kill-others-on-fail 'npm:test:unit' 'npm:test:integration'",
"test:watch": "concurrently --kill-others 'npm:test:unit:watch' 'npm:test:integration:watch'",
"test:unit": "vitest",
Expand Down Expand Up @@ -45,13 +45,13 @@
"copy-to-clipboard": "^3.3.3",
"deepmerge": "^4.3.1",
"moment": "^2.29.4",
"next": "14.2.14",
"next-intl": "^3.20.0",
"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": "^18.3.1",
"react-dom": "18.3.1",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"react-hook-form": "7.39.5",
"swr": "^2.2.0",
"tinycolor2": "1.4.2"
Expand All @@ -62,8 +62,8 @@
"@testing-library/react": "^16.0.1",
"@types/ms": "0.7.34",
"@types/node": "22.9.0",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
"@types/react": "npm:[email protected]",
"@types/react-dom": "npm:[email protected].1",
"@types/tinycolor2": "1.4.3",
"@types/uuid": "^10.0.0",
"@vercel/git-hooks": "1.0.0",
Expand Down
10 changes: 9 additions & 1 deletion apps/login/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ If the user has set up an additional **single** second factor, it is redirected

**NO MFA, FORCE MFA:** If no MFA method is available, and the settings force MFA, the user is sent to `/mfa/set` which prompts to setup a second factor.

**PROMPT PASSKEY** If the settings do not enforce MFA, we check if passkeys are allowed with `loginSettings?.passkeysType === PasskeysType.ALLOWED` and redirect the user to `/passkey/set` if no passkeys are setup. This step can be skipped.
**PROMPT PASSKEY** If the settings do not enforce MFA, we check if passkeys are allowed with `loginSettings?.passkeysType == PasskeysType.ALLOWED` and redirect the user to `/passkey/set` if no passkeys are setup. This step can be skipped.

If none of the previous conditions apply, we continue to sign in.

Expand Down Expand Up @@ -386,3 +386,11 @@ In future, self service options to jump to are shown below, like:
- logout

> NOTE: This page has to be explicitly enabled or act as a fallback if no default redirect is set.

## Currently NOT Supported

- loginSettings.disableLoginWithEmail
- loginSettings.disableLoginWithPhone
- loginSettings.allowExternalIdp - this will be deprecated with the new login as it can be determined by the available IDPs
- loginSettings.forceMfaLocalOnly
- loginSettings lifetimes - all besides Multifactor Init Check can be implemented. for the Init Check, an external storage or a timestamp has to be implemented which keeps track of the last verification
7 changes: 3 additions & 4 deletions apps/login/src/app/(login)/accounts/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ async function loadSessions() {
}
}

export default async function Page({
searchParams,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "accounts" });

Expand Down
7 changes: 3 additions & 4 deletions apps/login/src/app/(login)/authenticator/set/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ import {
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import { getLocale, getTranslations } from "next-intl/server";

export default async function Page({
searchParams,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "authenticator" });
const tError = await getTranslations({ locale, namespace: "error" });
Expand Down
10 changes: 4 additions & 6 deletions apps/login/src/app/(login)/idp/[provider]/failure/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ const PROVIDER_NAME_MAPPING: {
[IdentityProviderType.AZURE_AD]: "Microsoft",
};

export default async function Page({
searchParams,
params,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
params: { provider: string };
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
params: Promise<{ provider: string }>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "idp" });

Expand Down
11 changes: 5 additions & 6 deletions apps/login/src/app/(login)/idp/[provider]/success/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ async function loginFailed(branding?: BrandingSettings) {
</DynamicTheme>
);
}
export default async function Page({
searchParams,
params,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
params: { provider: string };
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
params: Promise<{ provider: string }>;
}) {
const params = await props.params;
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "idp" });
const { id, token, authRequestId, organization } = searchParams;
Expand Down
7 changes: 3 additions & 4 deletions apps/login/src/app/(login)/idp/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ function getIdentityProviders(orgId?: string) {
});
}

export default async function Page({
searchParams,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "idp" });

Expand Down
7 changes: 3 additions & 4 deletions apps/login/src/app/(login)/invite/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import {
} from "@/lib/zitadel";
import { getLocale, getTranslations } from "next-intl/server";

export default async function Page({
searchParams,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "invite" });

Expand Down
7 changes: 3 additions & 4 deletions apps/login/src/app/(login)/invite/success/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import { HumanUser, User } from "@zitadel/proto/zitadel/user/v2/user_pb";
import { getLocale, getTranslations } from "next-intl/server";
import Link from "next/link";

export default async function Page({
searchParams,
}: {
searchParams: Record<string | number | symbol, string | undefined>;
export default async function Page(props: {
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
}) {
const searchParams = await props.searchParams;
const locale = getLocale();
const t = await getTranslations({ locale, namespace: "invite" });

Expand Down
Loading
Loading