mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-11 22:32:17 +00:00
provider mappings
This commit is contained in:
@@ -1,14 +1,31 @@
|
|||||||
import { getBrandingSettings } from "@/lib/zitadel";
|
import { loadMostRecentSession } from "@/lib/session";
|
||||||
|
import { getBrandingSettings, getLoginSettings } from "@/lib/zitadel";
|
||||||
|
import Alert from "@/ui/Alert";
|
||||||
import DynamicTheme from "@/ui/DynamicTheme";
|
import DynamicTheme from "@/ui/DynamicTheme";
|
||||||
|
import UserAvatar from "@/ui/UserAvatar";
|
||||||
import VerifyEmailForm from "@/ui/VerifyEmailForm";
|
import VerifyEmailForm from "@/ui/VerifyEmailForm";
|
||||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
export default async function Page({ searchParams }: { searchParams: any }) {
|
export default async function Page({ searchParams }: { searchParams: any }) {
|
||||||
const { userId, sessionId, code, submit, organization, authRequestId } =
|
const {
|
||||||
searchParams;
|
userId,
|
||||||
|
loginName,
|
||||||
|
sessionId,
|
||||||
|
code,
|
||||||
|
submit,
|
||||||
|
organization,
|
||||||
|
authRequestId,
|
||||||
|
} = searchParams;
|
||||||
|
|
||||||
|
const sessionFactors = await loadMostRecentSession({
|
||||||
|
loginName,
|
||||||
|
organization,
|
||||||
|
});
|
||||||
|
|
||||||
const branding = await getBrandingSettings(organization);
|
const branding = await getBrandingSettings(organization);
|
||||||
|
|
||||||
|
const loginSettings = await getLoginSettings(organization);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicTheme branding={branding}>
|
<DynamicTheme branding={branding}>
|
||||||
<div className="flex flex-col items-center space-y-4">
|
<div className="flex flex-col items-center space-y-4">
|
||||||
@@ -17,14 +34,40 @@ export default async function Page({ searchParams }: { searchParams: any }) {
|
|||||||
Enter the Code provided in the verification email.
|
Enter the Code provided in the verification email.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{(!sessionFactors || !loginName) && (
|
||||||
|
<div className="py-4">
|
||||||
|
<Alert>
|
||||||
|
Could not get the context of the user. Make sure to enter the
|
||||||
|
username first or provide a loginName as searchParam.
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sessionFactors && (
|
||||||
|
<UserAvatar
|
||||||
|
loginName={loginName ?? sessionFactors.factors?.user?.loginName}
|
||||||
|
displayName={sessionFactors.factors?.user?.displayName}
|
||||||
|
showDropdown
|
||||||
|
searchParams={searchParams}
|
||||||
|
></UserAvatar>
|
||||||
|
)}
|
||||||
|
|
||||||
{userId ? (
|
{userId ? (
|
||||||
<VerifyEmailForm
|
<VerifyEmailForm
|
||||||
userId={userId}
|
userId={userId}
|
||||||
|
loginName={loginName}
|
||||||
code={code}
|
code={code}
|
||||||
submit={submit === "true"}
|
submit={submit === "true"}
|
||||||
organization={organization}
|
organization={organization}
|
||||||
authRequestId={authRequestId}
|
authRequestId={authRequestId}
|
||||||
sessionId={sessionId}
|
sessionId={sessionId}
|
||||||
|
loginSettings={loginSettings}
|
||||||
|
hasMfaSetUp={
|
||||||
|
!!sessionFactors?.factors?.otpEmail?.verifiedAt ||
|
||||||
|
!!sessionFactors?.factors?.otpSms?.verifiedAt ||
|
||||||
|
!!sessionFactors?.factors?.totp?.verifiedAt ||
|
||||||
|
!!sessionFactors?.factors?.webAuthN?.verifiedAt
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full flex flex-row items-center justify-center border border-yellow-600/40 dark:border-yellow-500/20 bg-yellow-200/30 text-yellow-600 dark:bg-yellow-700/20 dark:text-yellow-200 rounded-md py-2 scroll-px-40">
|
<div className="w-full flex flex-row items-center justify-center border border-yellow-600/40 dark:border-yellow-500/20 bg-yellow-200/30 text-yellow-600 dark:bg-yellow-700/20 dark:text-yellow-200 rounded-md py-2 scroll-px-40">
|
||||||
|
|||||||
@@ -35,6 +35,57 @@ export type OIDC_USER = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const OIDC_MAPPING = (idp: IDPInformation) => {
|
||||||
|
const rawInfo = idp.rawInformation as OIDC_USER;
|
||||||
|
|
||||||
|
return create(AddHumanUserRequestSchema, {
|
||||||
|
username: idp.userName,
|
||||||
|
email: {
|
||||||
|
email: rawInfo.User?.email,
|
||||||
|
verification: { case: "isVerified", value: true },
|
||||||
|
},
|
||||||
|
profile: {
|
||||||
|
displayName: rawInfo.User?.name ?? "",
|
||||||
|
givenName: rawInfo.User?.given_name ?? "",
|
||||||
|
familyName: rawInfo.User?.family_name ?? "",
|
||||||
|
},
|
||||||
|
idpLinks: [
|
||||||
|
{
|
||||||
|
idpId: idp.idpId,
|
||||||
|
userId: idp.userId,
|
||||||
|
userName: idp.userName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const GITHUB_MAPPING = (idp: IDPInformation) => {
|
||||||
|
const rawInfo = idp.rawInformation as {
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
return create(AddHumanUserRequestSchema, {
|
||||||
|
username: idp.userName,
|
||||||
|
email: {
|
||||||
|
email: rawInfo.email,
|
||||||
|
verification: { case: "isVerified", value: true },
|
||||||
|
},
|
||||||
|
profile: {
|
||||||
|
displayName: rawInfo.name ?? "",
|
||||||
|
givenName: rawInfo.name ?? "",
|
||||||
|
familyName: rawInfo.name ?? "",
|
||||||
|
},
|
||||||
|
idpLinks: [
|
||||||
|
{
|
||||||
|
idpId: idp.idpId,
|
||||||
|
userId: idp.userId,
|
||||||
|
userName: idp.userName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const PROVIDER_MAPPING: {
|
export const PROVIDER_MAPPING: {
|
||||||
[provider: string]: (rI: IDPInformation) => AddHumanUserRequest;
|
[provider: string]: (rI: IDPInformation) => AddHumanUserRequest;
|
||||||
} = {
|
} = {
|
||||||
@@ -62,6 +113,11 @@ export const PROVIDER_MAPPING: {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
[idpTypeToSlug(IdentityProviderType.GITLAB)]: OIDC_MAPPING,
|
||||||
|
[idpTypeToSlug(IdentityProviderType.GITLAB_SELF_HOSTED)]: OIDC_MAPPING,
|
||||||
|
[idpTypeToSlug(IdentityProviderType.OIDC)]: OIDC_MAPPING,
|
||||||
|
// check
|
||||||
|
[idpTypeToSlug(IdentityProviderType.OAUTH)]: OIDC_MAPPING,
|
||||||
[idpTypeToSlug(IdentityProviderType.AZURE_AD)]: (idp: IDPInformation) => {
|
[idpTypeToSlug(IdentityProviderType.AZURE_AD)]: (idp: IDPInformation) => {
|
||||||
const rawInfo = idp.rawInformation as {
|
const rawInfo = idp.rawInformation as {
|
||||||
jobTitle: string;
|
jobTitle: string;
|
||||||
@@ -76,8 +132,6 @@ export const PROVIDER_MAPPING: {
|
|||||||
userPrincipalName: string;
|
userPrincipalName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(rawInfo, rawInfo.userPrincipalName);
|
|
||||||
|
|
||||||
return create(AddHumanUserRequestSchema, {
|
return create(AddHumanUserRequestSchema, {
|
||||||
username: idp.userName,
|
username: idp.userName,
|
||||||
email: {
|
email: {
|
||||||
@@ -98,22 +152,26 @@ export const PROVIDER_MAPPING: {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[idpTypeToSlug(IdentityProviderType.GITHUB)]: (idp: IDPInformation) => {
|
[idpTypeToSlug(IdentityProviderType.GITHUB)]: GITHUB_MAPPING,
|
||||||
|
[idpTypeToSlug(IdentityProviderType.GITHUB_ES)]: GITHUB_MAPPING,
|
||||||
|
[idpTypeToSlug(IdentityProviderType.APPLE)]: (idp: IDPInformation) => {
|
||||||
const rawInfo = idp.rawInformation as {
|
const rawInfo = idp.rawInformation as {
|
||||||
email: string;
|
name?: string;
|
||||||
name: string;
|
firstName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
email?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
return create(AddHumanUserRequestSchema, {
|
return create(AddHumanUserRequestSchema, {
|
||||||
username: idp.userName,
|
username: idp.userName,
|
||||||
email: {
|
email: {
|
||||||
email: rawInfo.email,
|
email: rawInfo.email ?? "",
|
||||||
verification: { case: "isVerified", value: true },
|
verification: { case: "isVerified", value: true },
|
||||||
},
|
},
|
||||||
profile: {
|
profile: {
|
||||||
displayName: rawInfo.name ?? "",
|
displayName: rawInfo.name ?? "",
|
||||||
givenName: rawInfo.name ?? "",
|
givenName: rawInfo.firstName ?? "",
|
||||||
familyName: rawInfo.name ?? "",
|
familyName: rawInfo.lastName ?? "",
|
||||||
},
|
},
|
||||||
idpLinks: [
|
idpLinks: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ import { PROVIDER_MAPPING } from "./idp";
|
|||||||
|
|
||||||
const SESSION_LIFETIME_S = 3600;
|
const SESSION_LIFETIME_S = 3600;
|
||||||
|
|
||||||
console.log("Session lifetime", SESSION_LIFETIME_S);
|
|
||||||
|
|
||||||
const transport = createServerTransport(
|
const transport = createServerTransport(
|
||||||
process.env.ZITADEL_SERVICE_USER_TOKEN!,
|
process.env.ZITADEL_SERVICE_USER_TOKEN!,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -75,19 +75,23 @@ export default function SetPasswordForm({
|
|||||||
setError("Could not register user");
|
setError("Could not register user");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const params: any = { userId: response.userId };
|
|
||||||
|
|
||||||
|
const params = new URLSearchParams({ userId: response.userId });
|
||||||
|
|
||||||
|
if (response.factors?.user?.loginName) {
|
||||||
|
params.append("loginName", response.factors.user.loginName);
|
||||||
|
}
|
||||||
if (authRequestId) {
|
if (authRequestId) {
|
||||||
params.authRequestId = authRequestId;
|
params.append("authRequestId", authRequestId);
|
||||||
}
|
}
|
||||||
if (organization) {
|
if (organization) {
|
||||||
params.organization = organization;
|
params.append("organization", organization);
|
||||||
}
|
}
|
||||||
if (response && response.sessionId) {
|
if (response && response.sessionId) {
|
||||||
params.sessionId = response.sessionId;
|
params.append("sessionId", response.sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return router.push(`/verify?` + new URLSearchParams(params));
|
return router.push(`/verify?` + params);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { errors } = formState;
|
const { errors } = formState;
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import {
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { ReactNode, useState } from "react";
|
import { ReactNode, useState } from "react";
|
||||||
import Alert from "./Alert";
|
import Alert from "./Alert";
|
||||||
|
import { SignInWithApple } from "./idps/SignInWithApple";
|
||||||
import { SignInWithAzureAD } from "./idps/SignInWithAzureAD";
|
import { SignInWithAzureAD } from "./idps/SignInWithAzureAD";
|
||||||
|
import { SignInWithGeneric } from "./idps/SignInWithGeneric";
|
||||||
import { SignInWithGithub } from "./idps/SignInWithGithub";
|
import { SignInWithGithub } from "./idps/SignInWithGithub";
|
||||||
import { SignInWithGitlab } from "./idps/SignInWithGitlab";
|
import { SignInWithGitlab } from "./idps/SignInWithGitlab";
|
||||||
import { SignInWithGoogle } from "./idps/SignInWithGoogle";
|
import { SignInWithGoogle } from "./idps/SignInWithGoogle";
|
||||||
@@ -76,10 +78,41 @@ export function SignInWithIDP({
|
|||||||
{identityProviders &&
|
{identityProviders &&
|
||||||
identityProviders.map((idp, i) => {
|
identityProviders.map((idp, i) => {
|
||||||
switch (idp.type) {
|
switch (idp.type) {
|
||||||
|
case IdentityProviderType.APPLE:
|
||||||
|
return (
|
||||||
|
<SignInWithApple
|
||||||
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
|
onClick={() =>
|
||||||
|
navigateToAuthUrl(idp.id, IdentityProviderType.APPLE)
|
||||||
|
}
|
||||||
|
></SignInWithApple>
|
||||||
|
);
|
||||||
|
case IdentityProviderType.OAUTH:
|
||||||
|
return (
|
||||||
|
<SignInWithGeneric
|
||||||
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
|
onClick={() =>
|
||||||
|
navigateToAuthUrl(idp.id, IdentityProviderType.OAUTH)
|
||||||
|
}
|
||||||
|
></SignInWithGeneric>
|
||||||
|
);
|
||||||
|
case IdentityProviderType.OIDC:
|
||||||
|
return (
|
||||||
|
<SignInWithGeneric
|
||||||
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
|
onClick={() =>
|
||||||
|
navigateToAuthUrl(idp.id, IdentityProviderType.OIDC)
|
||||||
|
}
|
||||||
|
></SignInWithGeneric>
|
||||||
|
);
|
||||||
case IdentityProviderType.GITHUB:
|
case IdentityProviderType.GITHUB:
|
||||||
return (
|
return (
|
||||||
<SignInWithGithub
|
<SignInWithGithub
|
||||||
key={`idp-${i}`}
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToAuthUrl(idp.id, IdentityProviderType.GITHUB)
|
navigateToAuthUrl(idp.id, IdentityProviderType.GITHUB)
|
||||||
}
|
}
|
||||||
@@ -89,6 +122,7 @@ export function SignInWithIDP({
|
|||||||
return (
|
return (
|
||||||
<SignInWithGithub
|
<SignInWithGithub
|
||||||
key={`idp-${i}`}
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToAuthUrl(idp.id, IdentityProviderType.GITHUB_ES)
|
navigateToAuthUrl(idp.id, IdentityProviderType.GITHUB_ES)
|
||||||
}
|
}
|
||||||
@@ -98,6 +132,7 @@ export function SignInWithIDP({
|
|||||||
return (
|
return (
|
||||||
<SignInWithAzureAD
|
<SignInWithAzureAD
|
||||||
key={`idp-${i}`}
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToAuthUrl(idp.id, IdentityProviderType.AZURE_AD)
|
navigateToAuthUrl(idp.id, IdentityProviderType.AZURE_AD)
|
||||||
}
|
}
|
||||||
@@ -118,6 +153,7 @@ export function SignInWithIDP({
|
|||||||
return (
|
return (
|
||||||
<SignInWithGitlab
|
<SignInWithGitlab
|
||||||
key={`idp-${i}`}
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToAuthUrl(idp.id, IdentityProviderType.GITLAB)
|
navigateToAuthUrl(idp.id, IdentityProviderType.GITLAB)
|
||||||
}
|
}
|
||||||
@@ -127,6 +163,7 @@ export function SignInWithIDP({
|
|||||||
return (
|
return (
|
||||||
<SignInWithGitlab
|
<SignInWithGitlab
|
||||||
key={`idp-${i}`}
|
key={`idp-${i}`}
|
||||||
|
name={idp.name}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigateToAuthUrl(
|
navigateToAuthUrl(
|
||||||
idp.id,
|
idp.id,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { resendVerifyEmail, verifyUserByEmail } from "@/lib/server/email";
|
import { resendVerifyEmail, verifyUserByEmail } from "@/lib/server/email";
|
||||||
import Alert from "@/ui/Alert";
|
import Alert from "@/ui/Alert";
|
||||||
|
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
@@ -15,20 +16,26 @@ type Inputs = {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
loginName: string;
|
||||||
code: string;
|
code: string;
|
||||||
submit: boolean;
|
submit: boolean;
|
||||||
organization?: string;
|
organization?: string;
|
||||||
authRequestId?: string;
|
authRequestId?: string;
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
|
loginSettings?: LoginSettings;
|
||||||
|
hasMfaSetUp: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function VerifyEmailForm({
|
export default function VerifyEmailForm({
|
||||||
userId,
|
userId,
|
||||||
|
loginName,
|
||||||
code,
|
code,
|
||||||
submit,
|
submit,
|
||||||
organization,
|
organization,
|
||||||
authRequestId,
|
authRequestId,
|
||||||
sessionId,
|
sessionId,
|
||||||
|
loginSettings,
|
||||||
|
hasMfaSetUp,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { register, handleSubmit, formState } = useForm<Inputs>({
|
const { register, handleSubmit, formState } = useForm<Inputs>({
|
||||||
mode: "onBlur",
|
mode: "onBlur",
|
||||||
@@ -71,7 +78,7 @@ export default function VerifyEmailForm({
|
|||||||
userId,
|
userId,
|
||||||
}).catch((error: Error) => {
|
}).catch((error: Error) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setError(error.message);
|
setError(error.message ?? "Could not verify email");
|
||||||
});
|
});
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -81,6 +88,24 @@ export default function VerifyEmailForm({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loginSettings && loginSettings.forceMfa && !hasMfaSetUp) {
|
||||||
|
const params = new URLSearchParams({ checkAfter: "true" });
|
||||||
|
|
||||||
|
if (loginName) {
|
||||||
|
params.set("organization", loginName);
|
||||||
|
}
|
||||||
|
if (organization) {
|
||||||
|
params.set("organization", organization);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authRequestId && sessionId) {
|
||||||
|
params.set("authRequest", authRequestId);
|
||||||
|
params.set("sessionId", sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return router.push(`/mfa/set?` + params);
|
||||||
|
}
|
||||||
|
|
||||||
const params = new URLSearchParams({});
|
const params = new URLSearchParams({});
|
||||||
|
|
||||||
if (organization) {
|
if (organization) {
|
||||||
|
|||||||
36
apps/login/src/ui/idps/SignInWithApple.tsx
Normal file
36
apps/login/src/ui/idps/SignInWithApple.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ReactNode, forwardRef } from "react";
|
||||||
|
import { IdpButtonClasses, SignInWithIdentityProviderProps } from "./classes";
|
||||||
|
|
||||||
|
export const SignInWithApple = forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
SignInWithIdentityProviderProps
|
||||||
|
>(
|
||||||
|
({ children, className = "", name = "", ...props }, ref): ReactNode => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
ref={ref}
|
||||||
|
className={`${IdpButtonClasses} ${className}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className="h-12 w-12 flex items-center justify-center">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlSpace="preserve"
|
||||||
|
width="814"
|
||||||
|
height="1000"
|
||||||
|
>
|
||||||
|
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{children ? (
|
||||||
|
children
|
||||||
|
) : (
|
||||||
|
<span className="ml-4">{name ? name : "Sign in with Google"}</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
SignInWithApple.displayName = "SignInWithApple";
|
||||||
25
apps/login/src/ui/idps/SignInWithGeneric.tsx
Normal file
25
apps/login/src/ui/idps/SignInWithGeneric.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ReactNode, forwardRef } from "react";
|
||||||
|
import { IdpButtonClasses, SignInWithIdentityProviderProps } from "./classes";
|
||||||
|
|
||||||
|
export const SignInWithGeneric = forwardRef<
|
||||||
|
HTMLButtonElement,
|
||||||
|
SignInWithIdentityProviderProps
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{ children, className = "h-[50px] pl-20", name = "", ...props },
|
||||||
|
ref,
|
||||||
|
): ReactNode => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
ref={ref}
|
||||||
|
className={`${IdpButtonClasses} ${className}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children ? children : <span className="">{name}</span>}
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
SignInWithGeneric.displayName = "SignInWithGeneric";
|
||||||
9629
pnpm-lock.yaml
generated
9629
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user