Move external secrets behind auth broker

This commit is contained in:
Codex
2026-07-20 14:19:55 +09:00
parent ef0d53aa87
commit cb36612b88
14 changed files with 55 additions and 240 deletions
@@ -101,14 +101,12 @@ class PhoneLoginResponse {
required this.token,
required this.expiresAt,
required this.user,
this.orgContextCredential,
});
final String status;
final String token;
final DateTime expiresAt;
final LoginUser user;
final OrgContextCredential? orgContextCredential;
factory PhoneLoginResponse.fromJson(Map<String, dynamic> json) {
return PhoneLoginResponse(
@@ -116,9 +114,6 @@ class PhoneLoginResponse {
token: json['token'] as String? ?? json['accessToken'] as String? ?? '',
expiresAt: DateTime.parse(json['expiresAt'] as String),
user: LoginUser.fromJson(json['user'] as Map<String, dynamic>? ?? {}),
orgContextCredential: OrgContextCredential.fromJsonOrNull(
json['orgContextCredential'] ?? json['org_context'],
),
);
}
@@ -128,83 +123,10 @@ class PhoneLoginResponse {
'token': token,
'expiresAt': expiresAt.toUtc().toIso8601String(),
'user': user.toJson(),
if (orgContextCredential != null)
'orgContextCredential': orgContextCredential!.toJson(),
};
}
}
class OrgContextCredential {
const OrgContextCredential({
required this.baseUrl,
required this.tenantSlug,
required this.keyId,
required this.keySecret,
this.expiresAt,
});
final String baseUrl;
final String tenantSlug;
final String keyId;
final String keySecret;
final DateTime? expiresAt;
bool get isUsable {
return baseUrl.trim().isNotEmpty &&
tenantSlug.trim().isNotEmpty &&
keyId.trim().isNotEmpty &&
keySecret.trim().isNotEmpty &&
(expiresAt == null || expiresAt!.isAfter(DateTime.now().toUtc()));
}
factory OrgContextCredential.fromJson(Map<String, dynamic> json) {
return OrgContextCredential(
baseUrl: _readString(json, const ['baseUrl', 'base_url']),
tenantSlug: _readString(json, const ['tenantSlug', 'tenant_slug']),
keyId: _readString(json, const ['keyId', 'key_id']),
keySecret: _readString(json, const ['keySecret', 'key_secret']),
expiresAt: _readDate(json['expiresAt'] ?? json['expires_at']),
);
}
static OrgContextCredential? fromJsonOrNull(Object? value) {
if (value is! Map) {
return null;
}
final credential = OrgContextCredential.fromJson(
Map<String, dynamic>.from(value),
);
return credential.isUsable ? credential : null;
}
Map<String, dynamic> toJson() {
return {
'baseUrl': baseUrl,
'tenantSlug': tenantSlug,
'keyId': keyId,
'keySecret': keySecret,
if (expiresAt != null) 'expiresAt': expiresAt!.toUtc().toIso8601String(),
};
}
static String _readString(Map<String, dynamic> json, List<String> keys) {
for (final key in keys) {
final value = json[key];
if (value is String && value.trim().isNotEmpty) {
return value.trim();
}
}
return '';
}
static DateTime? _readDate(Object? value) {
if (value is! String || value.trim().isEmpty) {
return null;
}
return DateTime.tryParse(value)?.toUtc();
}
}
class PhoneLoginLinkInitRequest {
const PhoneLoginLinkInitRequest({
required this.phoneNumber,