Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/interfaces/IdentityProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export interface SSOIdentityProvider {
issuer: string;
client_id: string;
redirect_url?: string;
pkce: boolean;
jwks_url: string;
Comment on lines +80 to +81
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm whether the backend always returns pkce/jwks_url, and whether other consumers
# of SSOIdentityProvider rely on these fields being non-null.
rg -nP --type=ts -C3 '\b(pkce|jwks_url)\b'
rg -nP --type=ts -C2 'SSOIdentityProvider\b'

Repository: netbirdio/dashboard

Length of output: 9840


Make pkce and jwks_url optional on both SSOIdentityProvider and SSOIdentityProviderRequest.

The UI code initializes these fields with defaults:

  • provider?.pkce ?? false (line 100 of IdentityProviderModal.tsx)
  • provider?.jwks_url ?? "" (line 101 of IdentityProviderModal.tsx)

This pattern indicates the API may not return these fields in responses from older backends, creating a type contract violation. Existing code will silently receive undefined for these fields while the interfaces declare them as required string / boolean. Both interfaces need to make these optional for proper backward compatibility.

🛠️ Suggested type relaxation
 export interface SSOIdentityProvider {
   id: string;
   type: SSOIdentityProviderType;
   name: string;
   issuer: string;
   client_id: string;
   redirect_url?: string;
-  pkce: boolean;
-  jwks_url: string;
+  pkce?: boolean;
+  jwks_url?: string;
 }

 export interface SSOIdentityProviderRequest {
   type: SSOIdentityProviderType;
   name: string;
   issuer: string;
   client_id: string;
   client_secret: string;
-  pkce: boolean;
-  jwks_url: string;
+  pkce?: boolean;
+  jwks_url?: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pkce: boolean;
jwks_url: string;
pkce?: boolean;
jwks_url?: string;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/interfaces/IdentityProvider.ts` around lines 80 - 81, Update the type
definitions so pkce and jwks_url are optional on both SSOIdentityProvider and
SSOIdentityProviderRequest: change the required properties pkce and jwks_url to
optional properties (allowing undefined) in those interfaces so existing
backends that omit these fields won’t violate the type contract; adjust any
related type usages if necessary to handle undefined (e.g., use provider?.pkce
?? false and provider?.jwks_url ?? "" as the UI already does).

}

export interface SSOIdentityProviderRequest {
Expand All @@ -85,4 +87,6 @@ export interface SSOIdentityProviderRequest {
issuer: string;
client_id: string;
client_secret: string;
pkce: boolean;
jwks_url: string;
}
43 changes: 40 additions & 3 deletions src/modules/settings/IdentityProviderModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Button from "@components/Button";
import Code from "@components/Code";
import FancyToggleSwitch from "@components/FancyToggleSwitch";
import HelpText from "@components/HelpText";
import { Input } from "@components/Input";
import { Label } from "@components/Label";
Expand Down Expand Up @@ -30,6 +31,8 @@ import {
PlusCircle,
SaveIcon,
TagIcon,
ShieldCheck,
FileLock2,
} from "lucide-react";
import React, { useMemo, useState } from "react";
import { useSWRConfig } from "swr";
Expand Down Expand Up @@ -94,6 +97,8 @@ export default function IdentityProviderModal({
const [issuer, setIssuer] = useState(provider?.issuer ?? "");
const [clientId, setClientId] = useState(provider?.client_id ?? "");
const [clientSecret, setClientSecret] = useState("");
const [pkce, setPkce] = useState(provider?.pkce ?? false);
const [jwksUrl, setJwksUrl] = useState(provider?.jwks_url ?? "");

const requiresIssuer = type !== "google" && type !== "microsoft";

Expand All @@ -108,12 +113,13 @@ export default function IdentityProviderModal({
if (trimmedName.length === 0) return true;
if (requiresIssuer && trimmedIssuer.length === 0) return true;
if (trimmedClientId.length === 0) return true;
// Client secret required for new providers, or when client ID changed during edit
if ((!isEditing || clientIdChanged) && trimmedClientSecret.length === 0)
// Client secret required for new providers, or when client ID changed during edit,
// unless PKCE is enabled which allows public clients without a secret.
if ((!isEditing || clientIdChanged) && trimmedClientSecret.length === 0 && !pkce)
return true;

return false;
}, [name, issuer, clientId, clientSecret, isEditing, clientIdChanged, requiresIssuer]);
}, [name, issuer, clientId, clientSecret, isEditing, clientIdChanged, requiresIssuer, pkce]);

const submit = () => {
const payload: SSOIdentityProviderRequest = {
Expand All @@ -122,6 +128,8 @@ export default function IdentityProviderModal({
issuer: trim(issuer),
client_id: trim(clientId),
client_secret: trim(clientSecret),
pkce,
jwks_url: trim(jwksUrl),
};

if (isEditing) {
Expand Down Expand Up @@ -259,6 +267,35 @@ export default function IdentityProviderModal({
/>
</div>

<div>
<Label>JWKS URL (Optional)</Label>
<HelpText>
Override the default JSON Web Key Set URL from discovery
</HelpText>
<Input
placeholder={"https://login.example.com/common/discovery/keys"}
value={jwksUrl}
onChange={(e) => setJwksUrl(e.target.value)}
customPrefix={
<FileLock2 size={16} className="text-nb-gray-300" />
}
/>
</div>

<FancyToggleSwitch
value={pkce}
onChange={setPkce}
label={
<div className={"flex items-center gap-2"}>
<ShieldCheck size={16} />
Enable PKCE
</div>
}
helpText={
"Use Proof Key for Code Exchange (PKCE) for more secure authentication flows"
}
/>

<Separator />

<div>
Expand Down