@checkstack/auth-frontend 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @checkstack/auth-frontend
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [83557c7]
8
+ - Updated dependencies [83557c7]
9
+ - Updated dependencies [d316128]
10
+ - Updated dependencies [6dbfab8]
11
+ - @checkstack/ui@0.3.0
12
+ - @checkstack/common@0.4.0
13
+ - @checkstack/auth-common@0.5.1
14
+ - @checkstack/frontend-api@0.3.1
15
+
16
+ ## 0.5.0
17
+
18
+ ### Minor Changes
19
+
20
+ - d94121b: Add group-to-role mapping for SAML and LDAP authentication
21
+
22
+ **Features:**
23
+
24
+ - SAML and LDAP users can now be automatically assigned Checkstack roles based on their directory group memberships
25
+ - Configure group mappings in the authentication strategy settings with dynamic role dropdowns
26
+ - Managed role sync: roles configured in mappings are fully synchronized (added when user gains group, removed when user leaves group)
27
+ - Unmanaged roles (manually assigned, not in any mapping) are preserved during sync
28
+ - Optional default role for all users from a directory
29
+
30
+ **Bug Fix:**
31
+
32
+ - Fixed `x-options-resolver` not working for fields inside arrays with `.default([])` in DynamicForm schemas
33
+
34
+ ### Patch Changes
35
+
36
+ - 10aa9fb: Add SAML 2.0 SSO support
37
+
38
+ - Added new `auth-saml-backend` plugin for SAML 2.0 Single Sign-On authentication
39
+ - Supports SP-initiated SSO with configurable IdP metadata (URL or manual configuration)
40
+ - Uses samlify library for SAML protocol handling
41
+ - Configurable attribute mapping for user email/name extraction
42
+ - Automatic user creation and updates via S2S Identity API
43
+ - Added SAML redirect handling in LoginPage for seamless SSO flow
44
+
45
+ - Updated dependencies [d94121b]
46
+ - @checkstack/auth-common@0.5.0
47
+ - @checkstack/ui@0.2.4
48
+
3
49
  ## 0.4.1
4
50
 
5
51
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/auth-frontend",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "main": "src/index.tsx",
6
6
  "exports": {
@@ -1,8 +1,12 @@
1
+ import { useCallback, useMemo } from "react";
1
2
  import {
2
3
  StrategyConfigCard,
3
4
  type ConfigSection,
4
5
  type LucideIconName,
6
+ type OptionsResolver,
5
7
  } from "@checkstack/ui";
8
+ import { usePluginClient } from "@checkstack/frontend-api";
9
+ import { AuthApi } from "@checkstack/auth-common";
6
10
  import type { AuthStrategy } from "../api";
7
11
 
8
12
  export interface AuthStrategyCardProps {
@@ -30,6 +34,28 @@ export function AuthStrategyCard({
30
34
  onExpandedChange,
31
35
  config,
32
36
  }: AuthStrategyCardProps) {
37
+ const authClient = usePluginClient(AuthApi);
38
+
39
+ // Fetch all roles once for the dropdown options
40
+ const { data: roles = [] } = authClient.getRoles.useQuery({});
41
+
42
+ // Create resolver for dynamic role selection in group mapping
43
+ // Uses the already-fetched roles data
44
+ const roleOptionsResolver: OptionsResolver = useCallback(async () => {
45
+ return roles.map((role) => ({
46
+ value: role.id,
47
+ label: role.name,
48
+ }));
49
+ }, [roles]);
50
+
51
+ // Memoize the resolvers object to prevent unnecessary re-renders
52
+ const optionsResolvers = useMemo(
53
+ () => ({
54
+ roleOptions: roleOptionsResolver,
55
+ }),
56
+ [roleOptionsResolver],
57
+ );
58
+
33
59
  // Check if config schema has properties
34
60
  const hasConfigSchema =
35
61
  strategy.configSchema &&
@@ -40,7 +66,7 @@ export function AuthStrategyCard({
40
66
  // Config is missing if schema has properties but no saved config
41
67
  const configMissing = hasConfigSchema && strategy.config === undefined;
42
68
 
43
- // Build config sections
69
+ // Build config sections with role options resolver
44
70
  const configSections: ConfigSection[] = [];
45
71
  if (hasConfigSchema) {
46
72
  configSections.push({
@@ -48,6 +74,7 @@ export function AuthStrategyCard({
48
74
  title: "Configuration",
49
75
  schema: strategy.configSchema,
50
76
  value: config ?? strategy.config,
77
+ optionsResolvers,
51
78
  onSave: async (newConfig) => {
52
79
  await onSaveConfig(strategy.id, newConfig);
53
80
  },
@@ -54,7 +54,7 @@ export const LoginPage = () => {
54
54
 
55
55
  // Query: Registration status
56
56
  const { data: registrationData } = authClient.getRegistrationStatus.useQuery(
57
- {}
57
+ {},
58
58
  );
59
59
  const registrationAllowed = registrationData?.allowRegistration ?? true;
60
60
 
@@ -76,6 +76,11 @@ export const LoginPage = () => {
76
76
 
77
77
  const handleSocialLogin = async (provider: string) => {
78
78
  try {
79
+ // SAML uses a custom endpoint, not the better-auth OAuth flow
80
+ if (provider === "saml") {
81
+ globalThis.location.href = "/api/auth-saml/saml/login";
82
+ return;
83
+ }
79
84
  await authApi.signInWithSocial(provider);
80
85
  // Navigation will happen automatically after OAuth redirect
81
86
  } catch (error) {
@@ -142,8 +147,8 @@ export const LoginPage = () => {
142
147
  {hasCredential && hasSocial
143
148
  ? "Choose your preferred sign-in method"
144
149
  : hasCredential
145
- ? "Enter your credentials to access the dashboard"
146
- : "Continue with your account"}
150
+ ? "Enter your credentials to access the dashboard"
151
+ : "Continue with your account"}
147
152
  </CardDescription>
148
153
  </CardHeader>
149
154
  <CardContent>
@@ -280,7 +285,7 @@ export const LoginNavbarAction = () => {
280
285
  authClient.listAccounts().then((result) => {
281
286
  if (result.data) {
282
287
  const hasCredential = result.data.some(
283
- (account) => account.providerId === "credential"
288
+ (account) => account.providerId === "credential",
284
289
  );
285
290
  setHasCredentialAccount(hasCredential);
286
291
  }
@@ -295,7 +300,7 @@ export const LoginNavbarAction = () => {
295
300
  if (session?.user) {
296
301
  // Check if we have any bottom items to decide if we need a separator
297
302
  const bottomExtensions = pluginRegistry.getExtensions(
298
- UserMenuItemsBottomSlot.id
303
+ UserMenuItemsBottomSlot.id,
299
304
  );
300
305
  const hasBottomItems = bottomExtensions.length > 0;
301
306
  const menuContext: UserMenuItemsContext = {