1
0
forked from baron/baron-sso

Trusted RP 설정 UX 및 안내 문구 개선

This commit is contained in:
2026-03-30 13:03:04 +09:00
parent 3ffc345c2c
commit 3a057ee860
7 changed files with 71 additions and 72 deletions

View File

@@ -48,7 +48,7 @@ interface ScopeItem {
mandatory: boolean;
}
type SecurityProfile = "private" | "pkce" | "private_key_jwt";
type SecurityProfile = "private" | "pkce";
function readMetadataString(
metadata: Record<string, unknown>,
@@ -101,10 +101,11 @@ function ClientGeneralPage() {
const [tokenEndpointAuthMethod, setTokenEndpointAuthMethod] = useState<
"none" | "client_secret_basic" | "private_key_jwt"
>("client_secret_basic");
const [jwksSource, setJwksSource] = useState<"uri" | "inline">("uri");
const [jwksSource, setJwksSource] = useState<"uri" | "inline">("inline");
const [jwksUri, setJwksUri] = useState("");
const [jwksText, setJwksText] = useState("");
const [requestObjectSigningAlg, setRequestObjectSigningAlg] = useState("RS256");
const [headlessLoginEnabled, setHeadlessLoginEnabled] = useState(false);
const [scopes, setScopes] = useState<ScopeItem[]>(() => [
{
@@ -150,6 +151,8 @@ function ClientGeneralPage() {
if (typeof metadata.description === "string") setDescription(metadata.description);
if (typeof metadata.logo_url === "string") setLogoUrl(metadata.logo_url);
setHeadlessLoginEnabled(!!metadata.headless_login_enabled);
// Fallbacks from metadata if top-level fields are empty
if (!client.tokenEndpointAuthMethod) {
const metaAuth = readMetadataString(metadata, "token_endpoint_auth_method");
@@ -188,38 +191,25 @@ function ClientGeneralPage() {
}
}, [data]);
const securityProfile: SecurityProfile =
tokenEndpointAuthMethod === "private_key_jwt"
? "private_key_jwt"
: clientType === "pkce"
? "pkce"
: "private";
const headlessLoginEnabled = securityProfile === "private_key_jwt";
const securityProfile: SecurityProfile = clientType === "pkce" ? "pkce" : "private";
const handleSecurityProfileChange = (profile: SecurityProfile) => {
setClientType(profile);
if (profile === "pkce") {
setClientType("pkce");
setTokenEndpointAuthMethod("none");
setJwksUri("");
setJwksText("");
setRequestObjectSigningAlg("");
return;
setTokenEndpointAuthMethod(headlessLoginEnabled ? "private_key_jwt" : "none");
} else {
setTokenEndpointAuthMethod("client_secret_basic");
}
};
setClientType("private");
if (profile === "private_key_jwt") {
setTokenEndpointAuthMethod("private_key_jwt");
if (requestObjectSigningAlg.trim() === "") {
const handleHeadlessToggle = (enabled: boolean) => {
setHeadlessLoginEnabled(enabled);
if (clientType === "pkce") {
setTokenEndpointAuthMethod(enabled ? "private_key_jwt" : "none");
if (enabled && requestObjectSigningAlg.trim() === "") {
setRequestObjectSigningAlg("RS256");
}
return;
}
setTokenEndpointAuthMethod("client_secret_basic");
setJwksUri("");
setJwksText("");
setRequestObjectSigningAlg("");
};
const addScope = () => {
@@ -794,7 +784,7 @@ function ClientGeneralPage() {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid gap-4 md:grid-cols-3">
<div className="grid gap-4 md:grid-cols-2">
<label
className={cn(
"relative flex cursor-pointer flex-col gap-1 rounded-xl border-2 p-4 transition",
@@ -856,43 +846,34 @@ function ClientGeneralPage() {
<span className="absolute right-4 top-4 text-primary">
{securityProfile === "pkce" ? "✓" : ""}
</span>
</label>
<label
className={cn(
"relative flex cursor-pointer flex-col gap-1 rounded-xl border-2 p-4 transition",
securityProfile === "private_key_jwt"
? "border-primary bg-primary/5"
: "border-border bg-card hover:border-muted-foreground/40",
{securityProfile === "pkce" && (
<div
className="mt-4 pt-4 border-t border-primary/20 flex items-center justify-between"
onClick={(e) => e.stopPropagation()}
>
<div className="space-y-0.5">
<Label className="text-xs font-bold cursor-pointer" htmlFor="trusted-rp-toggle">
{t("ui.dev.clients.general.security.trusted_rp_enable", "Trusted RP (자체 로그인 UI 사용)")}
</Label>
<p className="text-[10px] text-muted-foreground">
{t("ui.dev.clients.general.security.trusted_rp_enable_help", "Baron SSO 로그인 창을 거치지 않고 애플리케이션 내의 자체 로그인 화면을 직접 구현하고 싶은 경우 활성화합니다.")}
</p>
</div>
<Switch
id="trusted-rp-toggle"
checked={headlessLoginEnabled}
onCheckedChange={handleHeadlessToggle}
/>
</div>
)}
>
<input
className="sr-only"
type="radio"
name="security-profile"
checked={securityProfile === "private_key_jwt"}
onChange={() => handleSecurityProfileChange("private_key_jwt")}
/>
<span className="flex items-center gap-2 text-sm font-bold uppercase text-foreground">
<Shield className="h-4 w-4 text-primary" />
{t("ui.dev.clients.general.security.trusted", "Trusted RP")}
</span>
<span className="whitespace-pre-line text-xs text-muted-foreground">
{t(
"msg.dev.clients.general.security.trusted_help",
"private_key_jwt와 공개키 등록을 사용해 trusted RP로 운영합니다. Headless Login은 이 프로필에서만 사용할 수 있습니다.",
)}
</span>
<span className="absolute right-4 top-4 text-primary">
{securityProfile === "private_key_jwt" ? "✓" : ""}
</span>
</label>
</div>
</CardContent>
</Card>
{/* 4. Public Key Registration (Trusted RP) */}
{securityProfile === "private_key_jwt" && (
{clientType === "pkce" && headlessLoginEnabled && (
<Card className="glass-panel border-primary/20">
<CardHeader className="pb-3">
<div className="flex flex-wrap items-start justify-between gap-3">
@@ -902,9 +883,6 @@ function ClientGeneralPage() {
"ui.dev.clients.general.public_key.title",
"Public Key Registration",
)}
<Badge variant="info" className="px-2 py-0.5 text-[10px] uppercase">
Trusted RP
</Badge>
</CardTitle>
<CardDescription>
{t(
@@ -928,7 +906,7 @@ function ClientGeneralPage() {
<p className="mt-1 text-xs text-muted-foreground">
{t(
"msg.dev.clients.general.public_key.headless_help",
"RP 자체 로그인 UI를 사용하고, 실제 인증 처리는 Baron Backend API를 통해 백그라운드에서 수행합니다.",
"애플리케이션 고유의 디자인으로 로그인 화면을 구성할 수 있습니다. 실제 아이디/비밀번호 확인 및 보안 검증 로직은 Baron API를 통해 백그라운드에서 처리됩니다.",
)}
</p>
</div>
@@ -985,21 +963,21 @@ function ClientGeneralPage() {
<input
type="radio"
name="jwksSource"
checked={jwksSource === "uri"}
onChange={() => setJwksSource("uri")}
checked={jwksSource === "inline"}
onChange={() => setJwksSource("inline")}
className="accent-primary"
/>
<span>JWKS URI ()</span>
<span>Inline Public Key</span>
</label>
<label className="flex items-center gap-2 text-sm">
<input
type="radio"
name="jwksSource"
checked={jwksSource === "inline"}
onChange={() => setJwksSource("inline")}
checked={jwksSource === "uri"}
onChange={() => setJwksSource("uri")}
className="accent-primary"
/>
<span>Inline Public Key ( )</span>
<span>JWKS URI</span>
</label>
</div>
@@ -1117,4 +1095,4 @@ function ClientGeneralPage() {
);
}
export default ClientGeneralPage;
export default ClientGeneralPage;

View File

@@ -401,7 +401,8 @@ guide_intro = "A JWKS URI is not created by Baron. It is the URL where the RP ba
guide_step_1 = "Generate a key pair on the RP server and keep the private key only in the RP backend."
guide_step_2 = "Expose the public key from the RP backend through a JWKS (JSON Web Key Set) endpoint."
guide_step_3 = "Enter a URL such as https://rp.example.com/.well-known/jwks.json in DevFront."
headless_help = "Trusted RPs can keep their own login UI while Baron continues to handle authentication and OIDC progression."
headless_help = "You can design your own login UI within the application. While the UI is yours, the actual identity verification and security checks are handled in the background via Baron's API."
jwks_inline_help = "Prefer the SSH-RSA public key format first. If you paste an 'ssh-rsa AAA...' key, Baron converts it to OIDC-standard JWKS (JSON) before saving."
jwks_uri_help = "Enter the public key endpoint URL exposed by the RP backend. Example: https://rp.example.com/.well-known/jwks.json"
request_object_alg_help = "Specify the JAR (Request Object) signing algorithm used for headless login."
source_help = "Register the JWKS URI served by the RP so Baron can verify the public key."
@@ -1393,6 +1394,8 @@ private = "Server Side App"
pkce = "PKCE"
trusted = "Trusted RP"
title = "Security Settings"
trusted_rp_enable = "Trusted RP (Custom Login UI)"
trusted_rp_enable_help = "Enable this if you want to implement your own login screen within the app instead of using the Baron SSO login page."
[ui.dev.clients.general.public_key]
auth_method = "Token Endpoint Auth Method"
@@ -1403,6 +1406,8 @@ guide_toggle = "JWKS URI Setup Guide"
headless_disabled = "Headless Disabled"
headless_enabled = "Headless Enabled"
headless_toggle = "Headless Login"
jwks_inline = "SSH-RSA or JWKS Public Key"
jwks_inline_placeholder = "Paste an 'ssh-rsa AAA...' public key first. JWKS (JSON) is also accepted if needed."
jwks_uri = "JWKS URI"
jwks_uri_placeholder = "https://rp.example.com/.well-known/jwks.json"
request_object_alg = "Request Object Signing Algorithm"

View File

@@ -401,10 +401,11 @@ guide_intro = "JWKS URI는 Baron이 만드는 값이 아니라 RP backend가 공
guide_step_1 = "RP 서버에서 key pair를 생성하고 private key는 RP backend에만 보관합니다."
guide_step_2 = "RP backend가 public key를 JWKS(JSON Web Key Set) 형태로 제공하는 endpoint를 준비합니다."
guide_step_3 = "예: https://rp.example.com/.well-known/jwks.json 같은 URL을 DevFront에 입력합니다."
headless_help = "Trusted RP는 RP 자체 로그인 UI를 사용할 수 있지만, bootstrap 검증, 사용자 인증 처리, Hydra 연계, 최종 redirect 생성은 Baron backend가 담당합니다."
headless_help = "애플리케이션 고유의 디자인으로 로그인 화면을 구성할 수 있습니다. 실제 아이디/비밀번호 확인 및 보안 검증 로직은 Baron API를 통해 백그라운드에서 처리됩니다."
jwks_inline_help = "SSH-RSA 공개키 형식을 우선 권장합니다. 'ssh-rsa AAA...' 형식으로 입력하면 Baron이 OIDC 표준인 JWKS(JSON)로 자동 변환하여 저장합니다."
jwks_uri_help = "RP backend가 제공하는 공개키 endpoint URL을 입력하세요. 예: https://rp.example.com/.well-known/jwks.json"
request_object_alg_help = "Headless Login을 사용할 때 JAR(Request Object) 서명 알고리즘을 명시합니다."
source_help = "운영 환경에서는 RP가 서빙하는 JWKS URI를 등록해 공개키를 검증합니다."
source_help = "애플리케이션의 공개키(SSH-RSA)를 직접 등록하거나, 운영 환경이라면 JWKS URI를 통해 자동으로 검증할 수 있습니다."
subtitle = "Trusted RP 판정에 필요한 공개키와 headless login 관련 설정을 관리합니다."
[msg.dev.clients.general.public_key.validation]
@@ -412,6 +413,7 @@ headless_requires_alg = "Headless Login을 사용하려면 Request Object Signin
headless_requires_private_key_jwt = "Headless Login을 사용하려면 token endpoint auth method가 private_key_jwt여야 합니다."
headless_requires_public_key = "Headless Login을 사용하려면 JWKS URI가 필요합니다."
invalid_jwks_uri = "JWKS URI 형식이 올바르지 않습니다."
missing_jwks_inline = "공개키(SSH-RSA 또는 JWKS)를 입력해야 합니다."
private_key_jwt_requires_public_key = "서명 키 기반 인증을 사용하려면 JWKS URI가 필요합니다."
[msg.dev.clients.help]
@@ -1390,8 +1392,10 @@ delete = "삭제"
[ui.dev.clients.general.security]
private = "Server side App"
pkce = "PKCE"
trusted = "Trusted RP"
title = "보안 설정"
trusted_rp_enable = "Trusted RP (자체 로그인 UI 사용)"
trusted_rp_enable_help = "Baron SSO 로그인 창을 거치지 않고 애플리케이션 내의 자체 로그인 화면을 직접 구현하고 싶은 경우 활성화합니다."
[ui.dev.clients.general.public_key]
auth_method = "Token Endpoint Auth Method"
@@ -1402,6 +1406,8 @@ guide_toggle = "JWKS URI 준비 가이드"
headless_disabled = "Headless Disabled"
headless_enabled = "Headless Enabled"
headless_toggle = "Headless Login"
jwks_inline = "SSH-RSA 또는 JWKS 공개키"
jwks_inline_placeholder = "'ssh-rsa AAA...' 형식의 공개키를 먼저 붙여넣으세요. 필요하면 JWKS (JSON)도 입력할 수 있습니다."
jwks_uri = "JWKS URI"
jwks_uri_placeholder = "https://rp.example.com/.well-known/jwks.json"
request_object_alg = "Request Object Signing Algorithm"

View File

@@ -402,6 +402,7 @@ guide_step_1 = ""
guide_step_2 = ""
guide_step_3 = ""
headless_help = ""
jwks_inline_help = ""
jwks_uri_help = ""
request_object_alg_help = ""
source_help = ""
@@ -1390,8 +1391,9 @@ delete = ""
[ui.dev.clients.general.security]
private = ""
pkce = ""
trusted = ""
title = ""
trusted_rp_enable = ""
trusted_rp_enable_help = ""
[ui.dev.clients.general.public_key]
auth_method = ""
@@ -1402,6 +1404,8 @@ guide_toggle = ""
headless_disabled = ""
headless_enabled = ""
headless_toggle = ""
jwks_inline = ""
jwks_inline_placeholder = ""
jwks_uri = ""
jwks_uri_placeholder = ""
request_object_alg = ""

View File

@@ -1459,6 +1459,8 @@ delete = "Delete"
private = "Server Side App"
pkce = "PKCE"
title = "Security Settings"
trusted_rp_enable = "Trusted RP (Custom Login UI)"
trusted_rp_enable_help = "Enable this if you want to implement your own login screen within the app instead of using the Baron SSO login page."
[ui.dev.clients.help]
docs_body = "Includes PKCE, client_secret_basic, redirect URI validation tips."

View File

@@ -1712,6 +1712,8 @@ title = "스코프"
private = "Server side App"
pkce = "PKCE"
title = "보안 설정"
trusted_rp_enable = "Trusted RP (자체 로그인 UI 사용)"
trusted_rp_enable_help = "Baron SSO 로그인 창을 거치지 않고 애플리케이션 내의 자체 로그인 화면을 직접 구현하고 싶은 경우 활성화합니다."
[ui.dev.dashboard.ops.card]
consent_revoked = "Consent 회수 건수"

View File

@@ -1706,6 +1706,8 @@ title = ""
private = ""
pkce = ""
title = ""
trusted_rp_enable = ""
trusted_rp_enable_help = ""
[ui.dev.dashboard.ops.card]
consent_revoked = ""