From 0c8c226acbae568074e20ac3550ac613872d40b5 Mon Sep 17 00:00:00 2001
From: masnwilliams <43387599+masnwilliams@users.noreply.github.com>
Date: Tue, 12 May 2026 20:34:01 +0000
Subject: [PATCH 1/4] auto-resolve sso provider icons via simple icons cdn
---
.../src/components/icons.tsx | 52 ------------
.../src/components/sso-provider.tsx | 82 +++++++++++--------
.../managed-auth-react/src/styles/styles.css | 12 +++
3 files changed, 62 insertions(+), 84 deletions(-)
diff --git a/packages/managed-auth-react/src/components/icons.tsx b/packages/managed-auth-react/src/components/icons.tsx
index a9a368d..1624e75 100644
--- a/packages/managed-auth-react/src/components/icons.tsx
+++ b/packages/managed-auth-react/src/components/icons.tsx
@@ -198,55 +198,3 @@ export const SpinnerIcon = (p: IconProps) => (
/>
);
-
-// SSO provider marks
-export const GoogleMark = (p: IconProps) => (
-
-);
-
-export const GitHubMark = (p: IconProps) => (
-
-);
-
-export const MicrosoftMark = (p: IconProps) => (
-
-);
-
-export const FacebookMark = (p: IconProps) => (
-
-);
-
-export const AppleMark = (p: IconProps) => (
-
-);
diff --git a/packages/managed-auth-react/src/components/sso-provider.tsx b/packages/managed-auth-react/src/components/sso-provider.tsx
index 87a2421..d82c32b 100644
--- a/packages/managed-auth-react/src/components/sso-provider.tsx
+++ b/packages/managed-auth-react/src/components/sso-provider.tsx
@@ -1,40 +1,58 @@
-import type { ReactNode } from "react";
-import {
- AppleMark,
- BuildingIcon,
- FacebookMark,
- GitHubMark,
- GoogleMark,
- KeyIcon,
- MicrosoftMark,
-} from "./icons";
+import { useState, type ReactNode } from "react";
+import { BuildingIcon, KeyIcon } from "./icons";
export interface SSOProviderInfo {
label: string;
icon: ReactNode;
}
+const NON_BRAND_ICONS: Record = {
+ passkey: { label: "Passkey", icon: },
+ sso: { label: "SSO", icon: },
+ saml: { label: "SSO", icon: },
+};
+
+function slugify(provider: string): string {
+ return provider.toLowerCase().replace(/[^a-z0-9]/g, "");
+}
+
+function titleCase(provider: string): string {
+ return provider
+ .split(/[\s_-]+/)
+ .filter(Boolean)
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
+ .join(" ");
+}
+
+function SSOProviderIcon({ provider }: { provider: string }) {
+ const [errored, setErrored] = useState(false);
+ const slug = slugify(provider);
+ const letter = provider.trim().charAt(0).toUpperCase() || "?";
+
+ if (!slug || errored) {
+ return (
+
+ {letter}
+
+ );
+ }
+
+ return (
+
setErrored(true)}
+ />
+ );
+}
+
export function getSSOProviderInfo(provider: string): SSOProviderInfo {
- const p = provider.toLowerCase();
- if (p.includes("google"))
- return { label: "Google", icon: };
- if (p.includes("github"))
- return { label: "GitHub", icon: };
- if (p.includes("microsoft") || p.includes("azure"))
- return {
- label: "Microsoft",
- icon: ,
- };
- if (p.includes("facebook"))
- return {
- label: "Facebook",
- icon: ,
- };
- if (p.includes("apple"))
- return { label: "Apple", icon: };
- if (p.includes("saml") || p.includes("sso"))
- return { label: "SSO", icon: };
- if (p.includes("passkey"))
- return { label: "Passkey", icon: };
- return { label: provider, icon: null };
+ const key = slugify(provider);
+ const nonBrand = NON_BRAND_ICONS[key];
+ if (nonBrand) return nonBrand;
+ return {
+ label: titleCase(provider),
+ icon: ,
+ };
}
diff --git a/packages/managed-auth-react/src/styles/styles.css b/packages/managed-auth-react/src/styles/styles.css
index ff3a2d5..c871c5e 100644
--- a/packages/managed-auth-react/src/styles/styles.css
+++ b/packages/managed-auth-react/src/styles/styles.css
@@ -510,6 +510,18 @@
height: 1.25rem;
}
+.kma-sso-icon--letter {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background: var(--kma-color-muted, #6b7280);
+ color: #fff;
+ font-size: 0.75rem;
+ font-weight: 600;
+ line-height: 1;
+}
+
/* ---------- Form / Input ---------- */
.kma-form {
From 3a4e6855b1944804d9e33f4e94fe73a107ea48ee Mon Sep 17 00:00:00 2001
From: Mason Williams
Date: Wed, 13 May 2026 17:00:38 -0400
Subject: [PATCH 2/4] Hybrid SSO icons: inline SVGs for top providers, Simple
Icons CDN fallback
Keep multicolor inline SVGs for Google, GitHub, GitLab, Microsoft,
Facebook, and Apple. Fall back to Simple Icons CDN for any other
provider, with a letter avatar as the final fallback.
Co-authored-by: Cursor
---
.../src/components/icons.tsx | 82 +++++++++++++++++++
.../src/components/sso-provider.tsx | 44 ++++++++--
2 files changed, 117 insertions(+), 9 deletions(-)
diff --git a/packages/managed-auth-react/src/components/icons.tsx b/packages/managed-auth-react/src/components/icons.tsx
index 1624e75..9dbd6af 100644
--- a/packages/managed-auth-react/src/components/icons.tsx
+++ b/packages/managed-auth-react/src/components/icons.tsx
@@ -198,3 +198,85 @@ export const SpinnerIcon = (p: IconProps) => (
/>
);
+
+// SSO provider marks
+export const GoogleMark = (p: IconProps) => (
+
+);
+
+export const GitHubMark = (p: IconProps) => (
+
+);
+
+export const GitLabMark = (p: IconProps) => (
+
+);
+
+export const MicrosoftMark = (p: IconProps) => (
+
+);
+
+export const FacebookMark = (p: IconProps) => (
+
+);
+
+export const AppleMark = (p: IconProps) => (
+
+);
diff --git a/packages/managed-auth-react/src/components/sso-provider.tsx b/packages/managed-auth-react/src/components/sso-provider.tsx
index d82c32b..7548de6 100644
--- a/packages/managed-auth-react/src/components/sso-provider.tsx
+++ b/packages/managed-auth-react/src/components/sso-provider.tsx
@@ -1,15 +1,34 @@
import { useState, type ReactNode } from "react";
-import { BuildingIcon, KeyIcon } from "./icons";
+import {
+ AppleMark,
+ BuildingIcon,
+ FacebookMark,
+ GitHubMark,
+ GitLabMark,
+ GoogleMark,
+ KeyIcon,
+ MicrosoftMark,
+} from "./icons";
export interface SSOProviderInfo {
label: string;
icon: ReactNode;
}
-const NON_BRAND_ICONS: Record = {
- passkey: { label: "Passkey", icon: },
- sso: { label: "SSO", icon: },
- saml: { label: "SSO", icon: },
+const BUILTIN_PROVIDERS: Record<
+ string,
+ { label: string; Icon: (p: { className?: string }) => ReactNode }
+> = {
+ google: { label: "Google", Icon: GoogleMark },
+ github: { label: "GitHub", Icon: GitHubMark },
+ gitlab: { label: "GitLab", Icon: GitLabMark },
+ microsoft: { label: "Microsoft", Icon: MicrosoftMark },
+ azure: { label: "Microsoft", Icon: MicrosoftMark },
+ facebook: { label: "Facebook", Icon: FacebookMark },
+ apple: { label: "Apple", Icon: AppleMark },
+ passkey: { label: "Passkey", Icon: KeyIcon },
+ sso: { label: "SSO", Icon: BuildingIcon },
+ saml: { label: "SSO", Icon: BuildingIcon },
};
function slugify(provider: string): string {
@@ -24,7 +43,7 @@ function titleCase(provider: string): string {
.join(" ");
}
-function SSOProviderIcon({ provider }: { provider: string }) {
+function CDNProviderIcon({ provider }: { provider: string }) {
const [errored, setErrored] = useState(false);
const slug = slugify(provider);
const letter = provider.trim().charAt(0).toUpperCase() || "?";
@@ -49,10 +68,17 @@ function SSOProviderIcon({ provider }: { provider: string }) {
export function getSSOProviderInfo(provider: string): SSOProviderInfo {
const key = slugify(provider);
- const nonBrand = NON_BRAND_ICONS[key];
- if (nonBrand) return nonBrand;
+
+ const builtin = BUILTIN_PROVIDERS[key];
+ if (builtin) {
+ return {
+ label: builtin.label,
+ icon: ,
+ };
+ }
+
return {
label: titleCase(provider),
- icon: ,
+ icon: ,
};
}
From 65cc025b41a811b5de5f42f5d787fd98a4a242e5 Mon Sep 17 00:00:00 2001
From: masnwilliams <43387599+masnwilliams@users.noreply.github.com>
Date: Tue, 12 May 2026 23:27:14 +0000
Subject: [PATCH 3/4] fix sso provider matching and stale error state
---
.../src/components/sso-provider.tsx | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/packages/managed-auth-react/src/components/sso-provider.tsx b/packages/managed-auth-react/src/components/sso-provider.tsx
index 7548de6..c387209 100644
--- a/packages/managed-auth-react/src/components/sso-provider.tsx
+++ b/packages/managed-auth-react/src/components/sso-provider.tsx
@@ -1,4 +1,4 @@
-import { useState, type ReactNode } from "react";
+import { useEffect, useState, type ReactNode } from "react";
import {
AppleMark,
BuildingIcon,
@@ -45,6 +45,7 @@ function titleCase(provider: string): string {
function CDNProviderIcon({ provider }: { provider: string }) {
const [errored, setErrored] = useState(false);
+ useEffect(() => setErrored(false), [provider]);
const slug = slugify(provider);
const letter = provider.trim().charAt(0).toUpperCase() || "?";
@@ -67,10 +68,13 @@ function CDNProviderIcon({ provider }: { provider: string }) {
}
export function getSSOProviderInfo(provider: string): SSOProviderInfo {
- const key = slugify(provider);
+ const slug = slugify(provider);
- const builtin = BUILTIN_PROVIDERS[key];
- if (builtin) {
+ const builtinKey = Object.keys(BUILTIN_PROVIDERS).find((k) =>
+ slug.includes(k),
+ );
+ if (builtinKey) {
+ const builtin = BUILTIN_PROVIDERS[builtinKey];
return {
label: builtin.label,
icon: ,
From d518bb4d2b2f510c6b7fa611c188914d8223a84e Mon Sep 17 00:00:00 2001
From: masnwilliams <43387599+masnwilliams@users.noreply.github.com>
Date: Tue, 12 May 2026 23:47:26 +0000
Subject: [PATCH 4/4] track errored slug to avoid stale fallback flash
useEffect runs after paint, so when the provider prop changes the
first render still sees errored=true and briefly shows the letter
avatar. Tracking the errored slug directly makes the check happen
during render.
---
packages/managed-auth-react/src/components/icons.tsx | 10 ++--------
.../managed-auth-react/src/components/sso-provider.tsx | 9 ++++-----
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/packages/managed-auth-react/src/components/icons.tsx b/packages/managed-auth-react/src/components/icons.tsx
index 9dbd6af..431bc57 100644
--- a/packages/managed-auth-react/src/components/icons.tsx
+++ b/packages/managed-auth-react/src/components/icons.tsx
@@ -230,10 +230,7 @@ export const GitHubMark = (p: IconProps) => (
export const GitLabMark = (p: IconProps) => (