1
0
forked from baron/baron-sso

code-check 오류 수정

This commit is contained in:
2026-03-30 13:29:36 +09:00
parent cfe97ecb1e
commit c96a5350a7
10 changed files with 302 additions and 69 deletions

View File

@@ -143,7 +143,7 @@ type clientUpsertRequest struct {
ResponseTypes *[]string `json:"responseTypes"`
TokenEndpointAuthMethod *string `json:"tokenEndpointAuthMethod"`
JwksUri *string `json:"jwksUri"`
Jwks interface{} `json:"jwks"`
Jwks interface{} `json:"jwks"`
Metadata *map[string]interface{} `json:"metadata"`
}

View File

@@ -49,6 +49,20 @@ interface ScopeItem {
}
type SecurityProfile = "private" | "pkce";
type TokenEndpointAuthMethod =
| "none"
| "client_secret_basic"
| "private_key_jwt";
function isTokenEndpointAuthMethod(
value: string,
): value is TokenEndpointAuthMethod {
return (
value === "none" ||
value === "client_secret_basic" ||
value === "private_key_jwt"
);
}
function readMetadataString(
metadata: Record<string, unknown>,
@@ -96,17 +110,17 @@ function ClientGeneralPage() {
const [status, setStatus] = useState<ClientStatus>("active");
const [initialStatus, setInitialStatus] = useState<ClientStatus>("active");
const [redirectUris, setRedirectUris] = useState("");
// Public Key Registration States
const [tokenEndpointAuthMethod, setTokenEndpointAuthMethod] = useState<
"none" | "client_secret_basic" | "private_key_jwt"
>("client_secret_basic");
const [tokenEndpointAuthMethod, setTokenEndpointAuthMethod] =
useState<TokenEndpointAuthMethod>("client_secret_basic");
const [jwksSource, setJwksSource] = useState<"uri" | "inline">("inline");
const [jwksUri, setJwksUri] = useState("");
const [jwksText, setJwksText] = useState("");
const [requestObjectSigningAlg, setRequestObjectSigningAlg] = useState("RS256");
const [requestObjectSigningAlg, setRequestObjectSigningAlg] =
useState("RS256");
const [headlessLoginEnabled, setHeadlessLoginEnabled] = useState(false);
const [scopes, setScopes] = useState<ScopeItem[]>(() => [
{
id: "1",
@@ -136,40 +150,55 @@ function ClientGeneralPage() {
setStatus(client.status);
setInitialStatus(client.status);
const savedAuthMethod = client.tokenEndpointAuthMethod || (client.type === "pkce" ? "none" : "client_secret_basic");
setTokenEndpointAuthMethod(savedAuthMethod as any);
const savedAuthMethod =
client.tokenEndpointAuthMethod ||
(client.type === "pkce" ? "none" : "client_secret_basic");
if (isTokenEndpointAuthMethod(savedAuthMethod)) {
setTokenEndpointAuthMethod(savedAuthMethod);
}
if (client.jwksUri) {
setJwksUri(client.jwksUri);
setJwksSource("uri");
} else if (client.jwks) {
setJwksText(typeof client.jwks === 'string' ? client.jwks : JSON.stringify(client.jwks, null, 2));
setJwksText(
typeof client.jwks === "string"
? client.jwks
: JSON.stringify(client.jwks, null, 2),
);
setJwksSource("inline");
}
const metadata = client.metadata ?? {};
if (typeof metadata.description === "string") setDescription(metadata.description);
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");
if (metaAuth === "none" || metaAuth === "client_secret_basic" || metaAuth === "private_key_jwt") {
setTokenEndpointAuthMethod(metaAuth);
}
const metaAuth = readMetadataString(
metadata,
"token_endpoint_auth_method",
);
if (isTokenEndpointAuthMethod(metaAuth)) {
setTokenEndpointAuthMethod(metaAuth);
}
}
if (!client.jwksUri && !client.jwks) {
const metaJwksUri = readMetadataString(metadata, "jwks_uri");
if (metaJwksUri) {
setJwksUri(metaJwksUri);
setJwksSource("uri");
}
const metaJwksUri = readMetadataString(metadata, "jwks_uri");
if (metaJwksUri) {
setJwksUri(metaJwksUri);
setJwksSource("uri");
}
}
const savedRequestObjectSigningAlg = readMetadataString(metadata, "request_object_signing_alg");
const savedRequestObjectSigningAlg = readMetadataString(
metadata,
"request_object_signing_alg",
);
if (savedRequestObjectSigningAlg) {
setRequestObjectSigningAlg(savedRequestObjectSigningAlg);
} else if (savedAuthMethod === "private_key_jwt") {
@@ -191,12 +220,15 @@ function ClientGeneralPage() {
}
}, [data]);
const securityProfile: SecurityProfile = clientType === "pkce" ? "pkce" : "private";
const securityProfile: SecurityProfile =
clientType === "pkce" ? "pkce" : "private";
const handleSecurityProfileChange = (profile: SecurityProfile) => {
setClientType(profile);
if (profile === "pkce") {
setTokenEndpointAuthMethod(headlessLoginEnabled ? "private_key_jwt" : "none");
setTokenEndpointAuthMethod(
headlessLoginEnabled ? "private_key_jwt" : "none",
);
} else {
setTokenEndpointAuthMethod("client_secret_basic");
}
@@ -261,15 +293,35 @@ function ClientGeneralPage() {
if (headlessLoginEnabled) {
if (jwksSource === "uri") {
if (!trimmedJwksUri) {
validationErrors.push(t("msg.dev.clients.general.public_key.validation.missing_jwks_uri", "JWKS URI를 입력해야 합니다."));
validationErrors.push(
t(
"msg.dev.clients.general.public_key.validation.missing_jwks_uri",
"JWKS URI를 입력해야 합니다.",
),
);
} else if (!isValidUrl(trimmedJwksUri)) {
validationErrors.push(t("msg.dev.clients.general.public_key.validation.invalid_jwks_uri", "JWKS URI 형식이 올바르지 않습니다."));
validationErrors.push(
t(
"msg.dev.clients.general.public_key.validation.invalid_jwks_uri",
"JWKS URI 형식이 올바르지 않습니다.",
),
);
}
} else if (jwksSource === "inline") {
if (!trimmedJwksText) {
validationErrors.push(t("msg.dev.clients.general.public_key.validation.missing_jwks_inline", "공개키(JWKS 또는 SSH-RSA)를 입력해야 합니다."));
validationErrors.push(
t(
"msg.dev.clients.general.public_key.validation.missing_jwks_inline",
"공개키(JWKS 또는 SSH-RSA)를 입력해야 합니다.",
),
);
} else if (!isValidJson(trimmedJwksText)) {
validationErrors.push(t("msg.dev.clients.general.public_key.validation.invalid_jwks_inline", "입력값이 유효한 JSON(JWKS) 형식이 아닙니다. SSH-RSA의 경우 'ssh-rsa'로 시작해야 합니다."));
validationErrors.push(
t(
"msg.dev.clients.general.public_key.validation.invalid_jwks_inline",
"입력값이 유효한 JSON(JWKS) 형식이 아닙니다. SSH-RSA의 경우 'ssh-rsa'로 시작해야 합니다.",
),
);
}
}
@@ -288,9 +340,13 @@ function ClientGeneralPage() {
const mutation = useMutation({
mutationFn: async () => {
const scopeNames = scopes.map((scope) => scope.name).filter(Boolean);
let finalJwks: any = undefined;
if (tokenEndpointAuthMethod === "private_key_jwt" && jwksSource === "inline" && trimmedJwksText) {
let finalJwks: ClientUpsertRequest["jwks"];
if (
tokenEndpointAuthMethod === "private_key_jwt" &&
jwksSource === "inline" &&
trimmedJwksText
) {
try {
finalJwks = JSON.parse(trimmedJwksText);
} catch (e) {
@@ -303,7 +359,10 @@ function ClientGeneralPage() {
type: clientType,
scopes: scopeNames,
tokenEndpointAuthMethod,
jwksUri: tokenEndpointAuthMethod === "private_key_jwt" && jwksSource === "uri" ? trimmedJwksUri : undefined,
jwksUri:
tokenEndpointAuthMethod === "private_key_jwt" && jwksSource === "uri"
? trimmedJwksUri
: undefined,
jwks: finalJwks,
metadata: {
description,
@@ -848,22 +907,32 @@ function ClientGeneralPage() {
</span>
{securityProfile === "pkce" && (
<div
<div
className="mt-4 pt-4 border-t border-primary/20 flex items-center justify-between"
onClick={(e) => e.stopPropagation()}
onKeyDown={(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
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 로그인 창을 거치지 않고 애플리케이션 내의 자체 로그인 화면을 직접 구현하고 싶은 경우 활성화합니다.")}
{t(
"ui.dev.clients.general.security.trusted_rp_enable_help",
"Baron SSO 로그인 창을 거치지 않고 애플리케이션 내의 자체 로그인 화면을 직접 구현하고 싶은 경우 활성화합니다.",
)}
</p>
</div>
<Switch
<Switch
id="trusted-rp-toggle"
checked={headlessLoginEnabled}
onCheckedChange={handleHeadlessToggle}
checked={headlessLoginEnabled}
onCheckedChange={handleHeadlessToggle}
/>
</div>
)}
@@ -910,7 +979,10 @@ function ClientGeneralPage() {
)}
</p>
</div>
<Badge variant="default" className="bg-primary/20 text-primary border-primary/30">
<Badge
variant="default"
className="bg-primary/20 text-primary border-primary/30"
>
{t("ui.common.enabled", "Enabled")}
</Badge>
</div>
@@ -984,7 +1056,10 @@ function ClientGeneralPage() {
{jwksSource === "uri" && (
<div className="space-y-2 animate-in fade-in slide-in-from-top-2">
<Label className="text-sm font-semibold">
{t("ui.dev.clients.general.public_key.jwks_uri", "JWKS URI")}
{t(
"ui.dev.clients.general.public_key.jwks_uri",
"JWKS URI",
)}
<span className="text-destructive ml-1">*</span>
</Label>
<Input
@@ -1007,14 +1082,20 @@ function ClientGeneralPage() {
{jwksSource === "inline" && (
<div className="space-y-2 animate-in fade-in slide-in-from-top-2">
<Label className="text-sm font-semibold">
{t("ui.dev.clients.general.public_key.jwks_inline", "JWKS 또는 OpenSSH 공개키")}
{t(
"ui.dev.clients.general.public_key.jwks_inline",
"JWKS 또는 OpenSSH 공개키",
)}
<span className="text-destructive ml-1">*</span>
</Label>
<Textarea
rows={8}
value={jwksText}
onChange={(e) => setJwksText(e.target.value)}
placeholder={t("ui.dev.clients.general.public_key.jwks_inline_placeholder", "JWKS (JSON) 또는 'ssh-rsa AAA...' 형식의 공개키를 붙여넣으세요.")}
placeholder={t(
"ui.dev.clients.general.public_key.jwks_inline_placeholder",
"JWKS (JSON) 또는 'ssh-rsa AAA...' 형식의 공개키를 붙여넣으세요.",
)}
className="font-mono text-xs leading-tight"
/>
<p className="text-xs text-muted-foreground">

View File

@@ -24,7 +24,7 @@ function toBase64Url(base64: string): string {
function hexToBase64Url(hex: string): string {
const binary = hex
.match(/.{1,2}/g)
?.map((byte) => String.fromCharCode(parseInt(byte, 16)))
?.map((byte) => String.fromCharCode(Number.parseInt(byte, 16)))
.join("");
if (!binary) return "";
return toBase64Url(btoa(binary));
@@ -42,12 +42,12 @@ export function parsePemToJwk(pem: string): JWK | null {
.replace(/-----END PUBLIC KEY-----/, "")
.replace(/\s/g, "");
// In a real browser environment without heavy libraries,
// we would need a full ASN.1 parser.
// In a real browser environment without heavy libraries,
// we would need a full ASN.1 parser.
// For now, we recommend using JWKS or OpenSSH formats for reliability,
// or we can hint the user that complex PEMs might fail.
// However, we'll try to support a basic one.
return null; // Placeholder: PEM parsing is complex without libs.
} catch (e) {
console.error("Failed to parse PEM", e);
@@ -100,12 +100,12 @@ export function parseSshRsaToJwk(sshKey: string): JWK | null {
}
function semanticsBase64Url(blob: string): string {
// Ensure leading zero removal for BigInt representations if necessary
let start = 0;
while (start < blob.length && blob.charCodeAt(start) === 0) {
start++;
}
return toBase64Url(btoa(blob.slice(start)));
// Ensure leading zero removal for BigInt representations if necessary
let start = 0;
while (start < blob.length && blob.charCodeAt(start) === 0) {
start++;
}
return toBase64Url(btoa(blob.slice(start)));
}
/**
@@ -114,7 +114,7 @@ function semanticsBase64Url(blob: string): string {
*/
export function tryConvertToJwks(input: string): string {
const trimmed = input.trim();
// 1. If it looks like JSON, return as is (validation happens in component)
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
return trimmed;
@@ -130,9 +130,9 @@ export function tryConvertToJwks(input: string): string {
// 3. PEM (Simplified check)
if (trimmed.includes("BEGIN PUBLIC KEY")) {
// For PEM, we suggest the user uses JWKS or SSH-RSA for now
// as JS doesn't have a built-in ASN1 parser and we want to avoid heavy deps.
return trimmed;
// For PEM, we suggest the user uses JWKS or SSH-RSA for now
// as JS doesn't have a built-in ASN1 parser and we want to avoid heavy deps.
return trimmed;
}
return trimmed;

View File

@@ -127,7 +127,9 @@ test.describe("DevFront clients lifecycle", () => {
page,
}) => {
const state = {
clients: [makeClient("client-trusted", { name: "Trusted App", type: "pkce" })],
clients: [
makeClient("client-trusted", { name: "Trusted App", type: "pkce" }),
],
consents: [] as Consent[],
auditLogsByCursor: undefined,
};
@@ -154,24 +156,30 @@ test.describe("DevFront clients lifecycle", () => {
.fill(sshRsaPublicKey);
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
await expect.poll(() => state.clients[0]?.tokenEndpointAuthMethod).toBe(
"private_key_jwt",
);
await expect
.poll(() => state.clients[0]?.tokenEndpointAuthMethod)
.toBe("private_key_jwt");
await expect
.poll(() => state.clients[0]?.metadata?.headless_login_enabled)
.toBe(true);
await expect
.poll(
() =>
(state.clients[0]?.jwks as { keys?: Array<{ kty?: string; alg?: string }> })
?.keys?.[0]?.kty,
(
state.clients[0]?.jwks as {
keys?: Array<{ kty?: string; alg?: string }>;
}
)?.keys?.[0]?.kty,
)
.toBe("RSA");
await expect
.poll(
() =>
(state.clients[0]?.jwks as { keys?: Array<{ kty?: string; alg?: string }> })
?.keys?.[0]?.alg,
(
state.clients[0]?.jwks as {
keys?: Array<{ kty?: string; alg?: string }>;
}
)?.keys?.[0]?.alg,
)
.toBe("RS256");

View File

@@ -234,6 +234,32 @@ limit_notice = "Showing members from the first 10 descendant organizations due t
[msg.admin.tenants.registry]
count = "{{count}} tenants loaded."
[msg.dev.clients.general.public_key]
auth_method_client_secret_basic_help = "Standard authentication method for server-side applications."
auth_method_none_help = "Use this for PKCE-based public clients."
auth_method_private_key_jwt_help = "Signed key-based client authentication recommended for trusted RP bootstrap and JAR verification."
guide_example = "Recommended example: https://rp.example.com/.well-known/jwks.json"
guide_intro = "A JWKS URI is not created by Baron. It is the URL where the RP backend exposes its public key."
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 = "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."
subtitle = "Manage the public key and headless login settings required for trusted RP evaluation."
[msg.dev.clients.general.public_key.validation]
headless_requires_alg = "Headless login requires a Request Object Signing Algorithm."
headless_requires_private_key_jwt = "Headless login requires token endpoint auth method to be private_key_jwt."
headless_requires_public_key = "Headless login requires a JWKS URI."
invalid_jwks_inline = "The input must be valid JSON (JWKS). For SSH-RSA input, it must start with 'ssh-rsa'."
invalid_jwks_uri = "JWKS URI format is invalid."
missing_jwks_inline = "Enter a public key in SSH-RSA or JWKS format."
missing_jwks_uri = "JWKS URI is required."
private_key_jwt_requires_public_key = "Signed key-based authentication requires a JWKS URI."
[msg.admin.tenants.schema]
empty = "No custom fields defined. Click \"Add Field\" to begin."
missing_id = "Tenant ID missing"
@@ -1215,6 +1241,7 @@ create = "Create"
delete = "Delete"
details = "Details"
edit = "Edit"
enabled = "Enabled"
export = "Export"
fail = "Fail"
go_home = "Go Home"
@@ -1462,6 +1489,26 @@ 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"
auth_method_client_secret_basic = "client_secret_basic"
auth_method_none = "none"
auth_method_private_key_jwt = "Signed Key Authentication"
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"
request_object_alg_placeholder = "RS256"
source = "Public Key Source"
source_uri = "JWKS URI"
title = "Public Key Registration"
validation_title = "Check before saving"
[ui.dev.clients.help]
docs_body = "Includes PKCE, client_secret_basic, redirect URI validation tips."
docs_title = "Docs & Examples"

View File

@@ -90,6 +90,7 @@ create = "생성"
delete = "삭제"
details = "상세정보"
edit = "편집"
enabled = "사용"
export = "내보내기"
fail = "실패"
go_home = "홈으로"
@@ -229,6 +230,32 @@ showing = "전체 {{total}}개 중 {{shown}}개를 표시하는 중입니다."
notice = "개발자 전용 콘솔입니다."
notice_detail = "연동 앱 등록 및 관리를 수행할 수 있습니다."
[msg.dev.clients.general.public_key]
auth_method_client_secret_basic_help = "일반적인 서버 사이드 앱 인증 방식입니다."
auth_method_none_help = "PKCE 기반 public client에 사용하는 방식입니다."
auth_method_private_key_jwt_help = "Trusted RP bootstrap과 JAR 검증에 필요한 서명 키 기반 인증 방식입니다."
guide_example = "권장 예시: https://rp.example.com/.well-known/jwks.json"
guide_intro = "JWKS URI는 Baron이 만드는 값이 아니라 RP backend가 공개키를 노출하는 URL입니다."
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 = "애플리케이션 고유의 디자인으로 로그인 화면을 구성할 수 있습니다. 실제 아이디/비밀번호 확인 및 보안 검증 로직은 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 = "애플리케이션의 공개키(SSH-RSA)를 직접 등록하거나, 운영 환경이라면 JWKS URI를 통해 자동으로 검증할 수 있습니다."
subtitle = "Trusted RP 판정에 필요한 공개키와 headless login 관련 설정을 관리합니다."
[msg.dev.clients.general.public_key.validation]
headless_requires_alg = "Headless Login을 사용하려면 Request Object Signing Algorithm을 입력해야 합니다."
headless_requires_private_key_jwt = "Headless Login을 사용하려면 token endpoint auth method가 private_key_jwt여야 합니다."
headless_requires_public_key = "Headless Login을 사용하려면 JWKS URI가 필요합니다."
invalid_jwks_inline = "입력값이 유효한 JSON(JWKS) 형식이 아닙니다. SSH-RSA의 경우 'ssh-rsa'로 시작해야 합니다."
invalid_jwks_uri = "JWKS URI 형식이 올바르지 않습니다."
missing_jwks_inline = "공개키(SSH-RSA 또는 JWKS)를 입력해야 합니다."
missing_jwks_uri = "JWKS URI를 입력해야 합니다."
private_key_jwt_requires_public_key = "서명 키 기반 인증을 사용하려면 JWKS URI가 필요합니다."
[msg.userfront.audit]
date = "접속일자: {{value}}"
device = "접속환경: {{value}}"
@@ -1715,6 +1742,26 @@ 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"
auth_method_client_secret_basic = "client_secret_basic"
auth_method_none = "none"
auth_method_private_key_jwt = "서명 키 기반 인증"
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"
request_object_alg_placeholder = "RS256"
source = "Public Key Source"
source_uri = "JWKS URI"
title = "공개키 등록"
validation_title = "저장 전 확인 필요"
[ui.dev.dashboard.ops.card]
consent_revoked = "Consent 회수 건수"
hydra_status = "Hydra 상태"

View File

@@ -90,6 +90,7 @@ create = ""
delete = ""
details = ""
edit = ""
enabled = ""
export = ""
fail = ""
go_home = ""
@@ -229,6 +230,32 @@ delete_confirm = ""
notice = ""
notice_detail = ""
[msg.dev.clients.general.public_key]
auth_method_client_secret_basic_help = ""
auth_method_none_help = ""
auth_method_private_key_jwt_help = ""
guide_example = ""
guide_intro = ""
guide_step_1 = ""
guide_step_2 = ""
guide_step_3 = ""
headless_help = ""
jwks_inline_help = ""
jwks_uri_help = ""
request_object_alg_help = ""
source_help = ""
subtitle = ""
[msg.dev.clients.general.public_key.validation]
headless_requires_alg = ""
headless_requires_private_key_jwt = ""
headless_requires_public_key = ""
invalid_jwks_inline = ""
invalid_jwks_uri = ""
missing_jwks_inline = ""
missing_jwks_uri = ""
private_key_jwt_requires_public_key = ""
[msg.userfront.audit]
date = ""
device = ""
@@ -1709,6 +1736,26 @@ title = ""
trusted_rp_enable = ""
trusted_rp_enable_help = ""
[ui.dev.clients.general.public_key]
auth_method = ""
auth_method_client_secret_basic = ""
auth_method_none = ""
auth_method_private_key_jwt = ""
guide_toggle = ""
headless_disabled = ""
headless_enabled = ""
headless_toggle = ""
jwks_inline = ""
jwks_inline_placeholder = ""
jwks_uri = ""
jwks_uri_placeholder = ""
request_object_alg = ""
request_object_alg_placeholder = ""
source = ""
source_uri = ""
title = ""
validation_title = ""
[ui.dev.dashboard.ops.card]
consent_revoked = ""
hydra_status = ""

View File

@@ -359,6 +359,7 @@ create = "Create"
delete = "Delete"
details = "Details"
edit = "Edit"
enabled = "Enabled"
export = "Export"
fail = "Fail"
go_home = "Go Home"

View File

@@ -37,6 +37,7 @@ create = "생성"
delete = "삭제"
details = "상세정보"
edit = "편집"
enabled = "사용"
export = "내보내기"
fail = "실패"
go_home = "홈으로"

View File

@@ -37,6 +37,7 @@ create = ""
delete = ""
details = ""
edit = ""
enabled = ""
export = ""
fail = ""
go_home = ""