Skip to content

OIDC PKCE support #16657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 2 additions & 1 deletion packages/backend-core/src/middleware/passport/sso/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export async function fetchStrategyConfig(
callbackUrl?: string
): Promise<OIDCStrategyConfiguration> {
try {
const { clientID, clientSecret, configUrl } = oidcConfig
const { clientID, clientSecret, configUrl, pkce } = oidcConfig

if (!clientID || !clientSecret || !callbackUrl || !configUrl) {
// check for remote config and all required elements
Expand All @@ -139,6 +139,7 @@ export async function fetchStrategyConfig(
clientID: clientID,
clientSecret: clientSecret,
callbackURL: callbackUrl,
pkce: pkce,
}
} catch (err) {
throw new Error(
Expand Down
17 changes: 15 additions & 2 deletions packages/backend-core/tests/core/utilities/structures/sso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SSOProfile,
SSOProviderType,
User,
PKCEMethod,
} from "@budibase/types"
import { generator } from "./generator"
import { email, uuid } from "./common"
Expand Down Expand Up @@ -69,8 +70,8 @@ export function ssoProfile(user?: User): SSOProfile {

// OIDC

export function oidcConfig(): OIDCInnerConfig {
return {
export function oidcConfig(pkce?: PKCEMethod): OIDCInnerConfig {
const config: OIDCInnerConfig = {
uuid: uuid(),
activated: true,
logo: "",
Expand All @@ -80,6 +81,18 @@ export function oidcConfig(): OIDCInnerConfig {
clientSecret: generator.string(),
scopes: [],
}

if (pkce) {
config.pkce = pkce
}

return config
}

export function oidcConfigWithPKCE(
method: PKCEMethod = PKCEMethod.S256
): OIDCInnerConfig {
return oidcConfig(method)
}

// response from .well-known/openid-configuration
Expand Down
5 changes: 2 additions & 3 deletions packages/bbui/src/Form/Core/Picker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
</span>
{:else}
<span class="option-extra icon field-icon">
<img src={fieldIcon} alt="icon" width="15" height="15" />
<img src={fieldIcon} alt="icon" style="height: 15px; width: auto;" />
</span>
{/if}
{/if}
Expand Down Expand Up @@ -237,8 +237,7 @@
<img
src={getOptionIcon(option, idx)}
alt="icon"
width="15"
height="15"
style="height: 15px; width: auto;"
/>
{:else}
<Icon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import { onMount } from "svelte"
import { API } from "@/api"
import { organisation, admin, licensing } from "@/stores/portal"
import { PKCEMethod } from "@budibase/types"
import Scim from "./scim.svelte"
import Google from "./google.svelte"

Expand All @@ -37,6 +38,11 @@

$: enforcedSSO = $organisation.isSSOEnforced

const pkceOptions = [
{ label: "S256 (recommended)", value: PKCEMethod.S256 },
{ label: "Plain", value: PKCEMethod.PLAIN },
]

$: OIDCConfigFields = {
Oidc: [
{ name: "configUrl", label: "Config URL" },
Expand Down Expand Up @@ -361,6 +367,14 @@
on:change={e => onFileSelected(e)}
bind:this={fileinput}
/>
<div class="form-row">
<Label size="L">PKCE Method</Label>
<Select
placeholder="None"
bind:value={providers.oidc.config.configs[0].pkce}
options={pkceOptions}
/>
</div>
<div class="form-row">
<Label size="L">Activated</Label>
<Toggle
Expand Down
7 changes: 7 additions & 0 deletions packages/types/src/documents/global/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export interface OIDCStrategyConfiguration {
clientID: string
clientSecret: string
callbackURL: string
pkce?: PKCEMethod
}

export interface OIDCConfigs {
Expand All @@ -94,6 +95,7 @@ export interface OIDCInnerConfig {
uuid: string
activated: boolean
scopes: string[]
pkce?: PKCEMethod
}

export interface OIDCConfig extends Config<OIDCConfigs> {}
Expand Down Expand Up @@ -166,6 +168,11 @@ export const isAIConfig = (config: Config): config is AIConfig =>
export const isRecaptchaConfig = (config: Config): config is RecaptchaConfig =>
config.type === ConfigType.RECAPTCHA

export enum PKCEMethod {
S256 = "S256",
PLAIN = "plain",
}

export enum ConfigType {
SETTINGS = "settings",
ACCOUNT = "account",
Expand Down
1 change: 1 addition & 0 deletions packages/worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"rimraf": "3.0.2",
"superagent": "^10.1.1",
"supertest": "6.3.3",
"testcontainers": "10.16.0",
"timekeeper": "2.2.0",
"typescript": "5.7.2"
},
Expand Down
5 changes: 3 additions & 2 deletions packages/worker/src/api/routes/global/configs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as controller from "../../controllers/global/configs"
import { auth } from "@budibase/backend-core"
import Joi from "joi"
import { ConfigType } from "@budibase/types"
import { ConfigType, PKCEMethod } from "@budibase/types"
import { adminRoutes, loggedInRoutes } from "../endpointGroups"

function smtpValidation() {
Expand Down Expand Up @@ -50,7 +50,8 @@ function oidcValidation() {
name: Joi.string().allow("", null),
uuid: Joi.string().required(),
activated: Joi.boolean().required(),
scopes: Joi.array().optional()
scopes: Joi.array().optional(),
pkce: Joi.string().valid(...Object.values(PKCEMethod)).optional()
})
).required()
}).unknown(true)
Expand Down
Loading
Loading