mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-13 16:42:34 +00:00
otp setup docs
This commit is contained in:
@@ -204,6 +204,8 @@ Requests to the APIs made:
|
||||
If the loginname decides to redirect the user to this page, a button to skip appears which will sign the user in afterwards.
|
||||
After a passkey is registered, we redirect the user to `/passkey` to verify it again and sign in with the new method. The `createPasskeyRegistrationLink()` uses the token of the session which is determined by the flow.
|
||||
|
||||
> NOTE: this page allows passkeys to be created only if the current session is valid (self service), or no authentication method is set (register). TODO: to be implemented.
|
||||
|
||||
> NOTE: Redirecting the user to `/passkey` will not be required in future and the currently used session will be hydrated directly after registering. (https://github.com/zitadel/zitadel/issues/8611)
|
||||
|
||||
### /otp/time-based/set
|
||||
@@ -212,10 +214,29 @@ This page registers a time based OTP method for a user.
|
||||
|
||||
<img src="./screenshots/otpset.png" alt="/otp/time-based/set" width="400px" />
|
||||
|
||||
Requests to the APIs made:
|
||||
|
||||
- `getBrandingSettings(org?)`
|
||||
- `getSession()`
|
||||
- `registerTOTP()`
|
||||
- `verifyTOTP()`
|
||||
|
||||
After the setup is done, the user is redirected to verify the TOTP method on `/otp/time-based`.
|
||||
|
||||
> NOTE: Redirecting the user to `/otp/time-based` will not be required in future and the currently used session will be hydrated directly. (https://github.com/zitadel/zitadel/issues/8611)
|
||||
|
||||
### /otp/email/set /otp/sms/set
|
||||
|
||||
This page registers either an Email OTP method or SMS OTP method for a user.
|
||||
|
||||
Requests to the APIs made:
|
||||
|
||||
- `getBrandingSettings(org?)`
|
||||
- `getSession()`
|
||||
- `addOTPEmail()` / `addOTPSMS()`
|
||||
|
||||
This page directly calls `addOTPEmail()` or `addOTPSMS()` when invoked and shows a success message.
|
||||
|
||||
### /u2f/set
|
||||
|
||||
This page registers a U2F method for a user.
|
||||
@@ -239,6 +260,8 @@ This page shows a register page, which gets firstname and lastname of a user as
|
||||
|
||||
<img src="./screenshots/register.png" alt="/register" width="400px" />
|
||||
|
||||
<img src="./screenshots/register_password.png" alt="register with password" width="400px" />
|
||||
|
||||
Requests to the APIs made:
|
||||
|
||||
- `listOrganizations()` :warning: TODO: determine the default organization if no context is set
|
||||
@@ -275,6 +298,21 @@ Both /success and /failure pages are designed to intercept the responses from th
|
||||
|
||||
### /verify
|
||||
|
||||
This page verifies the email to be valid. It page of the login can also be invoked without an active session.
|
||||
The context of the user is taken from the url and is set in the email template.
|
||||
|
||||
<img src="./screenshots/accounts.png" alt="/accounts" width="400px" />
|
||||
|
||||
Requests to the APIs made:
|
||||
|
||||
- `getBrandingSettings(org?)`
|
||||
- `getLoginSettings(org?)`
|
||||
- `verifyEmail()`
|
||||
|
||||
If the page is invoked with an active session (right after a register with password), the user is signed in or redirected to the loginname if no context is known.
|
||||
|
||||
> NOTE: This page will be extended to support invitations. In such case, authentication methods of the user are loaded and if none available, shown as possible next step (`/passkey/set`, `password/set`).
|
||||
|
||||
### /accounts
|
||||
|
||||
This page shows an overview of all current sessions.
|
||||
|
||||
BIN
apps/login/screenshots/register_password.png
Normal file
BIN
apps/login/screenshots/register_password.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
BIN
apps/login/screenshots/verify.png
Normal file
BIN
apps/login/screenshots/verify.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -31,8 +31,7 @@ export default async function Page({
|
||||
organization,
|
||||
});
|
||||
|
||||
let totpResponse: RegisterTOTPResponse | undefined,
|
||||
totpError: Error | undefined;
|
||||
let totpResponse: RegisterTOTPResponse | undefined, error: Error | undefined;
|
||||
if (session && session.factors?.user?.id) {
|
||||
if (method === "time-based") {
|
||||
await registerTOTP(session.factors.user.id)
|
||||
@@ -41,15 +40,21 @@ export default async function Page({
|
||||
totpResponse = resp;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
totpError = error;
|
||||
.catch((err) => {
|
||||
error = err;
|
||||
});
|
||||
} else if (method === "sms") {
|
||||
// does not work
|
||||
await addOTPSMS(session.factors.user.id);
|
||||
await addOTPSMS(session.factors.user.id).catch((error) => {
|
||||
console.error(error);
|
||||
error = new Error("Could not add OTP via SMS");
|
||||
});
|
||||
} else if (method === "email") {
|
||||
// works
|
||||
await addOTPEmail(session.factors.user.id);
|
||||
await addOTPEmail(session.factors.user.id).catch((error) => {
|
||||
console.error(error);
|
||||
error = new Error("Could not add OTP via Email");
|
||||
});
|
||||
} else {
|
||||
throw new Error("Invalid method");
|
||||
}
|
||||
@@ -98,9 +103,9 @@ export default async function Page({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{totpError && (
|
||||
{error && (
|
||||
<div className="py-4">
|
||||
<Alert>{totpError?.message}</Alert>
|
||||
<Alert>{error?.message}</Alert>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -119,8 +124,6 @@ export default async function Page({
|
||||
Scan the QR Code or navigate to the URL manually.
|
||||
</p>
|
||||
<div>
|
||||
{/* {auth && <div>{auth.to}</div>} */}
|
||||
|
||||
<TOTPRegister
|
||||
uri={totpResponse.uri as string}
|
||||
secret={totpResponse.secret as string}
|
||||
|
||||
@@ -74,39 +74,11 @@ export async function addOTPEmail(userId: string) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function addOTPSMS(userId: string, token?: string) {
|
||||
// TODO: Follow up here, I do not understand the branching
|
||||
// let userService;
|
||||
// if (token) {
|
||||
// const authConfig: ZitadelServerOptions = {
|
||||
// name: "zitadel login",
|
||||
// apiUrl: process.env.ZITADEL_API_URL ?? "",
|
||||
// token: token,
|
||||
// };
|
||||
// const sessionUser = initializeServer(authConfig);
|
||||
// userService = user.getUser(sessionUser);
|
||||
// } else {
|
||||
// userService = user.getUser(server);
|
||||
// }
|
||||
|
||||
export async function addOTPSMS(userId: string) {
|
||||
return userService.addOTPSMS({ userId }, {});
|
||||
}
|
||||
|
||||
export async function registerTOTP(userId: string, token?: string) {
|
||||
// TODO: Follow up here, I do not understand the branching
|
||||
// let userService;
|
||||
// if (token) {
|
||||
// const authConfig: ZitadelServerOptions = {
|
||||
// name: "zitadel login",
|
||||
// apiUrl: process.env.ZITADEL_API_URL ?? "",
|
||||
// token: token,
|
||||
// };
|
||||
//
|
||||
// const sessionUser = initializeServer(authConfig);
|
||||
// userService = user.getUser(sessionUser);
|
||||
// } else {
|
||||
// userService = user.getUser(server);
|
||||
// }
|
||||
export async function registerTOTP(userId: string) {
|
||||
return userService.registerTOTP({ userId }, {});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user