1
0
forked from baron/baron-sso

offline 스코프 제거, rp_claims 값 표준화

This commit is contained in:
2026-06-11 14:50:26 +09:00
parent f60b15a17b
commit c495e9119b
26 changed files with 1034 additions and 300 deletions

View File

@@ -72,7 +72,6 @@ error = "An error occurred while cancelling consent: {error}"
[msg.userfront.consent.scope]
email = "Email address (account identification and notifications)"
offline_access = "Offline access (keep signed in)"
openid = "OpenID authentication information (signin session check)"
phone = "Phone number (identity verification and notifications)"
profile = "Basic profile information (name, user identifier)"
@@ -706,4 +705,3 @@ toggle_label = "Show active sessions only"
[msg.userfront.audit.filter]
description = "Toggle to view only active sessions."

View File

@@ -297,7 +297,6 @@ error = "취소 처리 중 오류가 발생했습니다: {error}"
[msg.userfront.consent.scope]
email = "이메일 주소 (계정 식별 및 알림 용도)"
offline_access = "오프라인 접근 (로그인 유지)"
openid = "OpenID 인증 정보 (로그인 상태 확인)"
phone = "휴대폰 번호 (본인 인증 및 알림)"
profile = "기본 프로필 정보 (이름, 사용자 식별자)"
@@ -927,4 +926,3 @@ toggle_label = "활성 세션만 보기"
[msg.userfront.audit.filter]
description = "활성화된 세션만 보려면 토글을 켜주세요."

View File

@@ -269,7 +269,6 @@ error = ""
[msg.userfront.consent.scope]
email = ""
offline_access = ""
openid = ""
phone = ""
profile = ""
@@ -899,4 +898,3 @@ toggle_label = ""
[msg.userfront.audit.filter]
description = ""

View File

@@ -0,0 +1,11 @@
bool isRefreshTokenScopeAlias(String scope) {
final normalized = scope.trim().toLowerCase();
return normalized == 'offline' || normalized == 'offline_access';
}
List<String> filterConsentScopes(Iterable<String> scopes) {
return scopes
.map((scope) => scope.trim())
.where((scope) => scope.isNotEmpty && !isRefreshTokenScopeAlias(scope))
.toList(growable: false);
}

View File

@@ -6,6 +6,7 @@ import 'package:userfront/core/services/auth_proxy_service.dart';
import 'package:userfront/core/services/web_window.dart';
import 'package:userfront/core/ui/toast_service.dart';
import 'package:userfront/features/auth/domain/consent_error_routing.dart';
import 'package:userfront/features/auth/domain/consent_scope_policy.dart';
class ConsentScreen extends StatefulWidget {
final String consentChallenge;
@@ -53,10 +54,6 @@ class _ConsentScreenState extends State<ConsentScreen> {
'msg.userfront.consent.scope.email',
fallback: 'Email address (account identification and notifications)',
),
'offline_access': tr(
'msg.userfront.consent.scope.offline_access',
fallback: 'Offline access (keep signed in)',
),
'phone': tr(
'msg.userfront.consent.scope.phone',
fallback: 'Phone number (identity verification and notifications)',
@@ -80,9 +77,6 @@ class _ConsentScreenState extends State<ConsentScreen> {
}
String _scopeDisplayLabel(String scope) {
if (scope == 'offline_access') {
return 'offline access';
}
return scope.replaceAll('_', ' ');
}
@@ -138,9 +132,11 @@ class _ConsentScreenState extends State<ConsentScreen> {
}
// 초기 선택 상태 설정: 모든 요청된 스코프를 기본 선택
final requestedScopes =
(info['requested_scope'] as List<dynamic>?)?.cast<String>() ?? [];
final requestedScopes = filterConsentScopes(
(info['requested_scope'] as List<dynamic>?)?.cast<String>() ?? [],
);
_selectedScopes.addAll(requestedScopes);
info['requested_scope'] = requestedScopes;
setState(() {
_consentInfo = info;
@@ -299,9 +295,10 @@ class _ConsentScreenState extends State<ConsentScreen> {
? clientId
: tr('msg.userfront.consent.client_unknown'));
final clientLogo = _consentInfo?['client']?['logo_uri'];
final requestedScopes =
(_consentInfo?['requested_scope'] as List<dynamic>?)?.cast<String>() ??
[];
final requestedScopes = filterConsentScopes(
(_consentInfo?['requested_scope'] as List<dynamic>?)?.cast<String>() ??
[],
);
return SingleChildScrollView(
child: Container(

View File

@@ -597,7 +597,6 @@ const Map<String, String> koStrings = {
"msg.userfront.consent.missing_redirect": "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다.",
"msg.userfront.consent.redirect_notice": "동의 후 자동으로 서비스로 이동합니다.",
"msg.userfront.consent.scope.email": "이메일 주소 (계정 식별 및 알림 용도)",
"msg.userfront.consent.scope.offline_access": "오프라인 접근 (로그인 유지)",
"msg.userfront.consent.scope.openid": "OpenID 인증 정보 (로그인 상태 확인)",
"msg.userfront.consent.scope.phone": "휴대폰 번호 (본인 인증 및 알림)",
"msg.userfront.consent.scope.profile": "기본 프로필 정보 (이름, 사용자 식별자)",
@@ -2982,8 +2981,6 @@ const Map<String, String> enStrings = {
"After consent, you will be redirected automatically.",
"msg.userfront.consent.scope.email":
"Email address (account identification and notifications)",
"msg.userfront.consent.scope.offline_access":
"Offline access (keep signed in)",
"msg.userfront.consent.scope.openid":
"OpenID authentication information (signin session check)",
"msg.userfront.consent.scope.phone":

View File

@@ -0,0 +1,25 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:userfront/features/auth/domain/consent_scope_policy.dart';
void main() {
group('consent scope policy', () {
test('filters offline scope aliases from requested consent scopes', () {
expect(
filterConsentScopes([
'openid',
' offline ',
'profile',
'offline_access',
'email',
]),
['openid', 'profile', 'email'],
);
});
test('detects refresh token scope aliases case-insensitively', () {
expect(isRefreshTokenScopeAlias('OFFLINE'), isTrue);
expect(isRefreshTokenScopeAlias(' offline_access '), isTrue);
expect(isRefreshTokenScopeAlias('profile'), isFalse);
});
});
}