Configure 'Auto Login with External IDP' via blueprints #617

Closed
opened 2026-04-05 17:27:26 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @oschwartz10612 on 11/19/2025

Discussed in https://github.com/orgs/fosrl/discussions/1761

Originally posted by dephekt October 27, 2025

Summary

I'd like to be able to enable the Auto Login with External IDP setting either via:

  • an org level setting making it default behavior
  • setting a relevant auth config label blueprint on the container

Motivation

I don't want to set the "Auto Login with External IDP" setting on every resource in the UI when I already use blueprints to convey similar config state to Pangolin. And I don't want to write and manage a separate script just to ensure new resources are configured with the setting.

Proposed Solution

I reviewed the NextJS frontend to understand how it determines the state of the UI element in the resource auth configuration dashboard. I see here it posts to the resource to essentially patch it with skipToIdpId: selectedIdpId. This exposes it in the resource schema like this:

$ xh https://api.pangolin.net/v1/resource/123456789 -A bearer -a $PANGOLIN_API | jq '.data'
{
  "resourceId": 123456789,
  "resourceGuid": "foobar",
  "orgId": "org_foobarbaz",
  "niceId": "foobar",
  "name": "FooBar",
  ...
  "setHostHeader": null,
  "enableProxy": true,
  "skipToIdpId": 123456,
  "headers": null
}

Clearly the resource model already supports it and there's an endpoint to set and update the key. So it seems this setting just needs exposed and wired up in the relevant blueprint model. I found that here in server/lib/blueprints/types.ts:

export const AuthSchema = z.object({
    // pincode has to have 6 digits
    pincode: z.number().min(100000).max(999999).optional(),
    password: z.string().min(1).optional(),
    "basic-auth": z.object({
        user: z.string().min(1),
        password: z.string().min(1)
    }).optional(),
    "sso-enabled": z.boolean().optional().default(false),
+   "sso-redirect-idp": z.number().int().positive().optional().nullable(),
    "sso-roles": z
        .array(z.string())
        .optional()
        .default([])
        .refine((roles) => !roles.includes("Admin"), {
            message: "Admin role cannot be included in sso-roles"
        }),
    "sso-users": z.array(z.string().email()).optional().default([]),
    "whitelist-users": z.array(z.string().email()).optional().default([]),
});

Then I think it needs wired to the resource creation in server/lib/blueprints/proxyResources.ts here and similarly during the resource update here.

            const [newResource] = await trx
                .insert(resources)
                .values({
                    orgId,
                    niceId: resourceNiceId,
                    name: resourceData.name || "Unnamed Resource",
                    protocol: protocol || "tcp",
                    http: http,
                    proxyPort: http ? null : resourceData["proxy-port"],
                    fullDomain: http ? resourceData["full-domain"] : null,
                    subdomain: domain ? domain.subdomain : null,
                    domainId: domain ? domain.domainId : null,
                    enabled: resourceEnabled,
                    sso: resourceData.auth?.["sso-enabled"] || false,
+                   skipToIdpId: resourceData.auth?.["sso-redirect-idp"] || null,
                    setHostHeader: resourceData["host-header"] || null,
                    tlsServerName: resourceData["tls-server-name"] || null,
                    ssl: resourceSsl,
                    headers: headers || null,
                    applyRules:
                        resourceData.rules && resourceData.rules.length > 0
                })

Alternatives Considered

I could easily script setting the configuration via the API. It's just another thing to manage and remember, when I prefer to consolidate the resource config within the Docker labels. Keeping it in sync becomes another thing to deal with also.

It's worth considering if it should be an org or other higher level setting, or such a higher setting that can override at the resource level.

Additional Context

No response

*Originally created by @oschwartz10612 on 11/19/2025* ### Discussed in https://github.com/orgs/fosrl/discussions/1761 <div type='discussions-op-text'> <sup>Originally posted by **dephekt** October 27, 2025</sup> ### Summary I'd like to be able to enable the Auto Login with External IDP setting either via: - an org level setting making it default behavior - setting a relevant auth config label blueprint on the container ### Motivation I don't want to set the "Auto Login with External IDP" setting on every resource in the UI when I already use blueprints to convey similar config state to Pangolin. And I don't want to write and manage a separate script just to ensure new resources are configured with the setting. ### Proposed Solution I reviewed the NextJS frontend to understand how it determines the state of the UI element in the resource auth configuration dashboard. I see [here](https://github.com/fosrl/pangolin/blob/cabf3e96952cfcdc40452f1a4e39800129025801/src/app/%5BorgId%5D/settings/resources/%5BniceId%5D/authentication/page.tsx#L340-L344) it posts to the resource to essentially patch it with `skipToIdpId: selectedIdpId`. This exposes it in the resource schema like this: ```json $ xh https://api.pangolin.net/v1/resource/123456789 -A bearer -a $PANGOLIN_API | jq '.data' { "resourceId": 123456789, "resourceGuid": "foobar", "orgId": "org_foobarbaz", "niceId": "foobar", "name": "FooBar", ... "setHostHeader": null, "enableProxy": true, "skipToIdpId": 123456, "headers": null } ``` Clearly the resource model already supports it and there's an endpoint to set and update the key. So it seems this setting just needs exposed and wired up in the relevant blueprint model. I found that [here](https://github.com/fosrl/pangolin/blob/cabf3e96952cfcdc40452f1a4e39800129025801/server/lib/blueprints/types.ts#L41-L59) in server/lib/blueprints/types.ts: ```diff export const AuthSchema = z.object({ // pincode has to have 6 digits pincode: z.number().min(100000).max(999999).optional(), password: z.string().min(1).optional(), "basic-auth": z.object({ user: z.string().min(1), password: z.string().min(1) }).optional(), "sso-enabled": z.boolean().optional().default(false), + "sso-redirect-idp": z.number().int().positive().optional().nullable(), "sso-roles": z .array(z.string()) .optional() .default([]) .refine((roles) => !roles.includes("Admin"), { message: "Admin role cannot be included in sso-roles" }), "sso-users": z.array(z.string().email()).optional().default([]), "whitelist-users": z.array(z.string().email()).optional().default([]), }); ``` Then I think it needs wired to the resource creation in server/lib/blueprints/proxyResources.ts [here](https://github.com/fosrl/pangolin/blob/cabf3e96952cfcdc40452f1a4e39800129025801/server/lib/blueprints/proxyResources.ts#L581-L602) and similarly during the resource update [here](https://github.com/fosrl/pangolin/blob/cabf3e96952cfcdc40452f1a4e39800129025801/server/lib/blueprints/proxyResources.ts#L213). ```diff const [newResource] = await trx .insert(resources) .values({ orgId, niceId: resourceNiceId, name: resourceData.name || "Unnamed Resource", protocol: protocol || "tcp", http: http, proxyPort: http ? null : resourceData["proxy-port"], fullDomain: http ? resourceData["full-domain"] : null, subdomain: domain ? domain.subdomain : null, domainId: domain ? domain.domainId : null, enabled: resourceEnabled, sso: resourceData.auth?.["sso-enabled"] || false, + skipToIdpId: resourceData.auth?.["sso-redirect-idp"] || null, setHostHeader: resourceData["host-header"] || null, tlsServerName: resourceData["tls-server-name"] || null, ssl: resourceSsl, headers: headers || null, applyRules: resourceData.rules && resourceData.rules.length > 0 }) ``` ### Alternatives Considered I could easily script setting the configuration via the API. It's just another thing to manage and remember, when I prefer to consolidate the resource config within the Docker labels. Keeping it in sync becomes another thing to deal with also. It's worth considering if it should be an org or other higher level setting, or such a higher setting that can override at the resource level. ### Additional Context _No response_</div>
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/pangolin#617