feat: add Hanzo IAM OIDC SSO provider
- Add HanzoIAMProvider to NextAuth config (OIDC with userinfo endpoint) - Add "Continue with Hanzo" button to login page (first SSO option) - Env vars: HANZO_IAM_URL, HANZO_IAM_CLIENT_ID, HANZO_IAM_CLIENT_SECRET - IAM app registered as app-dataroom in init_data.json
This commit is contained in:
@@ -32,7 +32,7 @@ export default function Login() {
|
||||
const isSSORequired = authError === "require-saml-sso";
|
||||
|
||||
const [lastUsed, setLastUsed] = useLastUsed();
|
||||
const authMethods = ["google", "email", "linkedin", "passkey"] as const;
|
||||
const authMethods = ["hanzo", "google", "email", "linkedin", "passkey"] as const;
|
||||
type AuthMethod = (typeof authMethods)[number];
|
||||
const [clickedMethod, setClickedMethod] = useState<AuthMethod | undefined>(
|
||||
undefined,
|
||||
@@ -166,6 +166,30 @@ export default function Login() {
|
||||
</form>
|
||||
<p className="py-4 text-center">or</p>
|
||||
<div className="flex flex-col space-y-2 px-4 sm:px-12">
|
||||
<div className="relative">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setClickedMethod("hanzo");
|
||||
setLastUsed("hanzo");
|
||||
signIn("hanzo-iam", {
|
||||
...(next && next.length > 0 ? { callbackUrl: next } : {}),
|
||||
}).then(() => {
|
||||
setClickedMethod(undefined);
|
||||
});
|
||||
}}
|
||||
loading={clickedMethod === "hanzo"}
|
||||
disabled={clickedMethod && clickedMethod !== "hanzo"}
|
||||
className="flex w-full items-center justify-center space-x-2 border border-red-500 bg-red-500 font-normal text-white hover:bg-red-600"
|
||||
>
|
||||
<svg className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
||||
</svg>
|
||||
<span>Continue with Hanzo</span>
|
||||
{clickedMethod !== "hanzo" && lastUsed === "hanzo" && (
|
||||
<LastUsed />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import CredentialsProvider from "next-auth/providers/credentials";
|
||||
import EmailProvider from "next-auth/providers/email";
|
||||
import GoogleProvider from "next-auth/providers/google";
|
||||
import LinkedInProvider from "next-auth/providers/linkedin";
|
||||
import type { OAuthConfig } from "next-auth/providers/oauth";
|
||||
|
||||
import { identifyUser, trackAnalytics } from "@/lib/analytics";
|
||||
import { qstash } from "@/lib/cron";
|
||||
@@ -24,6 +25,37 @@ import { getIpAddress } from "@/lib/utils/ip";
|
||||
|
||||
const VERCEL_DEPLOYMENT = !!process.env.VERCEL_URL;
|
||||
|
||||
const HANZO_IAM_URL = process.env.HANZO_IAM_URL;
|
||||
const HANZO_IAM_CLIENT_ID = process.env.HANZO_IAM_CLIENT_ID;
|
||||
const HANZO_IAM_CLIENT_SECRET = process.env.HANZO_IAM_CLIENT_SECRET;
|
||||
|
||||
function HanzoIAMProvider(): OAuthConfig<any> {
|
||||
const issuer = HANZO_IAM_URL || "https://hanzo.id";
|
||||
return {
|
||||
id: "hanzo-iam",
|
||||
name: process.env.HANZO_IAM_PROVIDER_NAME || "Hanzo",
|
||||
type: "oauth",
|
||||
wellKnown: `${issuer}/.well-known/openid-configuration`,
|
||||
clientId: HANZO_IAM_CLIENT_ID || "",
|
||||
clientSecret: HANZO_IAM_CLIENT_SECRET || "",
|
||||
authorization: { params: { scope: "openid profile email" } },
|
||||
idToken: false,
|
||||
userinfo: { url: `${issuer}/oauth/userinfo` },
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name:
|
||||
profile.displayName ||
|
||||
profile.name ||
|
||||
profile.preferred_username,
|
||||
email: profile.email,
|
||||
image: profile.avatar || profile.picture,
|
||||
};
|
||||
},
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
};
|
||||
}
|
||||
|
||||
function getMainDomainUrl(): string {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return process.env.NEXTAUTH_URL || "http://localhost:3000";
|
||||
@@ -41,6 +73,7 @@ export const authOptions: NextAuthOptions = {
|
||||
error: "/login",
|
||||
},
|
||||
providers: [
|
||||
...(HANZO_IAM_CLIENT_ID ? [HanzoIAMProvider()] : []),
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID as string,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
|
||||
|
||||
Reference in New Issue
Block a user