@rodit/rodit-auth-be 9.12.0 → 9.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +1712 -2324
- package/index.js +14 -2
- package/lib/auth/tokenservice.js +153 -33
- package/lib/middleware/authenticationmw.js +70 -3
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -26,7 +26,11 @@ const {
|
|
|
26
26
|
|
|
27
27
|
const {
|
|
28
28
|
validate_jwt_token_be,
|
|
29
|
-
generate_jwt_token
|
|
29
|
+
generate_jwt_token,
|
|
30
|
+
normalizeUrlWithoutPort,
|
|
31
|
+
isNonEmptyUrlClaim,
|
|
32
|
+
isFederatedRoditLogin,
|
|
33
|
+
validateFederatedLoginTarget,
|
|
30
34
|
} = require('./lib/auth/tokenservice');
|
|
31
35
|
|
|
32
36
|
const validatepermissions = require('./lib/middleware/validatepermissionsmw');
|
|
@@ -1033,6 +1037,7 @@ class RoditClient {
|
|
|
1033
1037
|
*
|
|
1034
1038
|
* @param {Object} [lsoptions] - Optional settings
|
|
1035
1039
|
* @param {string} [lsoptions.loginPath] - Login path (default /api/login)
|
|
1040
|
+
* @param {string} [lsoptions.apiEndpoint] - Federated API URL to authenticate against (MITM-checked via JWT rodit_subjectuniqueidentifier_url)
|
|
1036
1041
|
* @returns {Promise<Object>} Login result with token
|
|
1037
1042
|
*/
|
|
1038
1043
|
async login_server(lsoptions = {}) {
|
|
@@ -1043,7 +1048,10 @@ class RoditClient {
|
|
|
1043
1048
|
component: 'RoditClient',
|
|
1044
1049
|
method: 'login_server',
|
|
1045
1050
|
requestId,
|
|
1046
|
-
lsoptions: {
|
|
1051
|
+
lsoptions: {
|
|
1052
|
+
loginPath: lsoptions.loginPath,
|
|
1053
|
+
apiEndpoint: lsoptions.apiEndpoint,
|
|
1054
|
+
}
|
|
1047
1055
|
});
|
|
1048
1056
|
|
|
1049
1057
|
try {
|
|
@@ -1929,6 +1937,10 @@ module.exports = {
|
|
|
1929
1937
|
logout_server,
|
|
1930
1938
|
validate_jwt_token_be,
|
|
1931
1939
|
generate_jwt_token,
|
|
1940
|
+
normalizeUrlWithoutPort,
|
|
1941
|
+
isNonEmptyUrlClaim,
|
|
1942
|
+
isFederatedRoditLogin,
|
|
1943
|
+
validateFederatedLoginTarget,
|
|
1932
1944
|
validatepermissions,
|
|
1933
1945
|
webhookHandler,
|
|
1934
1946
|
// Webhook identity + session helpers (key travels with the webhook; trust is
|
package/lib/auth/tokenservice.js
CHANGED
|
@@ -70,6 +70,85 @@ function extractLoginPeerRoditIdFromSub(sub) {
|
|
|
70
70
|
return subParts.length > 1 ? subParts[1] : "";
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function normalizeUrlWithoutPort(url) {
|
|
74
|
+
if (!url) return "";
|
|
75
|
+
try {
|
|
76
|
+
const parsedUrl = new URL(url);
|
|
77
|
+
parsedUrl.port = "";
|
|
78
|
+
return parsedUrl.toString();
|
|
79
|
+
} catch (_e) {
|
|
80
|
+
return String(url);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isNonEmptyUrlClaim(value) {
|
|
85
|
+
return typeof value === "string" && value.trim() !== "";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** True when login peer and issuing server declare different API URLs (federated login). */
|
|
89
|
+
function isFederatedRoditLogin(peer_rodit, own_rodit) {
|
|
90
|
+
const peerUrl = peer_rodit?.metadata?.subjectuniqueidentifier_url;
|
|
91
|
+
const ownUrl = own_rodit?.metadata?.subjectuniqueidentifier_url;
|
|
92
|
+
if (!peerUrl || !ownUrl) return false;
|
|
93
|
+
return normalizeUrlWithoutPort(peerUrl) !== normalizeUrlWithoutPort(ownUrl);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Client MITM check after JWT crypto validation.
|
|
98
|
+
* Federated attempt = intendedApiEndpoint differs from client home URL.
|
|
99
|
+
*
|
|
100
|
+
* @param {Object} payload - Verified JWT payload
|
|
101
|
+
* @param {string} intendedApiEndpoint - URL the client connected to for login
|
|
102
|
+
* @param {string} clientHomeSubjectUrl - Client RODiT subjectuniqueidentifier_url
|
|
103
|
+
* @returns {{ ok: boolean, federated?: boolean, errorCode?: string, errorMessage?: string }}
|
|
104
|
+
*/
|
|
105
|
+
function validateFederatedLoginTarget(
|
|
106
|
+
payload,
|
|
107
|
+
intendedApiEndpoint,
|
|
108
|
+
clientHomeSubjectUrl
|
|
109
|
+
) {
|
|
110
|
+
const normalizedIntended = normalizeUrlWithoutPort(intendedApiEndpoint);
|
|
111
|
+
const normalizedClientHome = normalizeUrlWithoutPort(clientHomeSubjectUrl);
|
|
112
|
+
const isFederatedAttempt = normalizedClientHome !== normalizedIntended;
|
|
113
|
+
|
|
114
|
+
if (!isFederatedAttempt) {
|
|
115
|
+
return { ok: true, federated: false };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const federatedIssuerUrl = payload?.rodit_subjectuniqueidentifier_url;
|
|
119
|
+
if (!isNonEmptyUrlClaim(federatedIssuerUrl)) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
federated: true,
|
|
123
|
+
errorCode: "FEDERATED_ISSUER_MISSING",
|
|
124
|
+
errorMessage:
|
|
125
|
+
"Federated login JWT has null/empty rodit_subjectuniqueidentifier_url",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (normalizeUrlWithoutPort(federatedIssuerUrl) !== normalizedIntended) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
federated: true,
|
|
133
|
+
errorCode: "FEDERATED_ISSUER_MISMATCH",
|
|
134
|
+
errorMessage:
|
|
135
|
+
"rodit_subjectuniqueidentifier_url does not match login apiEndpoint",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (normalizeUrlWithoutPort(payload?.iss) !== normalizedClientHome) {
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
federated: true,
|
|
143
|
+
errorCode: "FEDERATED_ISSUER_MISMATCH",
|
|
144
|
+
errorMessage:
|
|
145
|
+
"JWT iss does not match client home subjectuniqueidentifier_url",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { ok: true, federated: true };
|
|
150
|
+
}
|
|
151
|
+
|
|
73
152
|
function parseRoditJwtDurationSeconds(metadata) {
|
|
74
153
|
const parsed = parseInt(metadata?.jwt_duration, 10);
|
|
75
154
|
if (Number.isFinite(parsed) && parsed > 0) {
|
|
@@ -750,6 +829,7 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
750
829
|
|
|
751
830
|
const jwtSignStart = Date.now();
|
|
752
831
|
const { SignJWT } = await getJose();
|
|
832
|
+
const federatedLogin = isFederatedRoditLogin(peer_rodit, own_rodit);
|
|
753
833
|
const token = await new SignJWT({
|
|
754
834
|
iss: peer_rodit.metadata.subjectuniqueidentifier_url,
|
|
755
835
|
sub:
|
|
@@ -776,6 +856,10 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
776
856
|
rodit_allowedcidr: peer_rodit.metadata.allowed_cidr,
|
|
777
857
|
rodit_allowediso3166list: peer_rodit.metadata.allowed_iso3166list,
|
|
778
858
|
rodit_webhookurl: peer_rodit.metadata.webhook_url,
|
|
859
|
+
// Always present (null when same-API); EdDSA covers the claim like any other
|
|
860
|
+
rodit_subjectuniqueidentifier_url: federatedLogin
|
|
861
|
+
? own_rodit.metadata.subjectuniqueidentifier_url
|
|
862
|
+
: null,
|
|
779
863
|
config_iso639: null,
|
|
780
864
|
config_iso3166: null,
|
|
781
865
|
config_iso15924: null,
|
|
@@ -802,6 +886,7 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
802
886
|
jwtId,
|
|
803
887
|
sessionId: session_id,
|
|
804
888
|
sessionStatus: session_status,
|
|
889
|
+
federatedLogin,
|
|
805
890
|
tokenValidFor: tokenExpiration - now,
|
|
806
891
|
sessionValidFor: sessionExpiration - now
|
|
807
892
|
});
|
|
@@ -1060,6 +1145,11 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
1060
1145
|
rodit_webhookcidr: token.rodit_webhookcidr,
|
|
1061
1146
|
rodit_allowedcidr: token.rodit_allowedcidr,
|
|
1062
1147
|
rodit_webhookurl: token.rodit_webhookurl,
|
|
1148
|
+
rodit_subjectuniqueidentifier_url: isNonEmptyUrlClaim(
|
|
1149
|
+
token.rodit_subjectuniqueidentifier_url
|
|
1150
|
+
)
|
|
1151
|
+
? token.rodit_subjectuniqueidentifier_url
|
|
1152
|
+
: null,
|
|
1063
1153
|
config_iso639: null,
|
|
1064
1154
|
config_iso3166: null,
|
|
1065
1155
|
config_iso15924: null,
|
|
@@ -1555,46 +1645,71 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
1555
1645
|
throw new Error("Error 006: Token is not yet valid");
|
|
1556
1646
|
}
|
|
1557
1647
|
|
|
1558
|
-
// Function to normalize URL by removing port
|
|
1559
|
-
const normalizeUrlWithoutPort = (url) => {
|
|
1560
|
-
if (!url) return '';
|
|
1561
|
-
try {
|
|
1562
|
-
// Use URL constructor to parse the URL
|
|
1563
|
-
const parsedUrl = new URL(url);
|
|
1564
|
-
// Remove the port
|
|
1565
|
-
parsedUrl.port = '';
|
|
1566
|
-
// Return the normalized URL as a string
|
|
1567
|
-
return parsedUrl.toString();
|
|
1568
|
-
} catch (e) {
|
|
1569
|
-
// If URL parsing fails, return the original URL
|
|
1570
|
-
return url;
|
|
1571
|
-
}
|
|
1572
|
-
};
|
|
1573
|
-
|
|
1574
|
-
// Normalize both URLs for comparison
|
|
1575
|
-
const normalizedTokenIssuer = normalizeUrlWithoutPort(payload.iss);
|
|
1576
|
-
const normalizedExpectedIssuer = normalizeUrlWithoutPort(rodit.metadata.subjectuniqueidentifier_url);
|
|
1577
|
-
|
|
1578
1648
|
// Issuer check with enhanced logging
|
|
1649
|
+
const federatedIssuerUrl = payload.rodit_subjectuniqueidentifier_url;
|
|
1650
|
+
const isFederatedJwt = isNonEmptyUrlClaim(federatedIssuerUrl);
|
|
1651
|
+
const normalizedTokenIssuer = normalizeUrlWithoutPort(payload.iss);
|
|
1652
|
+
const normalizedOwnSubjectUrl = normalizeUrlWithoutPort(
|
|
1653
|
+
rodit.metadata.subjectuniqueidentifier_url
|
|
1654
|
+
);
|
|
1655
|
+
|
|
1579
1656
|
logger.debug("Detailed issuer validation information", {
|
|
1580
1657
|
component: "JwtAuth",
|
|
1581
1658
|
method: "validate_jwt_token_be",
|
|
1582
1659
|
requestId,
|
|
1583
1660
|
tokenIssuer: payload.iss,
|
|
1584
1661
|
expectedIssuer: rodit.metadata.subjectuniqueidentifier_url,
|
|
1662
|
+
federatedIssuerUrl,
|
|
1585
1663
|
normalizedTokenIssuer,
|
|
1586
|
-
|
|
1664
|
+
normalizedOwnSubjectUrl,
|
|
1587
1665
|
roditId: rodit.token_id,
|
|
1588
1666
|
roditOwnerId: rodit.owner_id,
|
|
1589
1667
|
hasMetadata: !!rodit.metadata,
|
|
1590
1668
|
metadataKeys: rodit.metadata ? Object.keys(rodit.metadata) : [],
|
|
1591
1669
|
payloadKeys: Object.keys(payload),
|
|
1592
|
-
|
|
1593
|
-
normalizedIssuerMatch: normalizedTokenIssuer === normalizedExpectedIssuer
|
|
1670
|
+
isFederatedJwt,
|
|
1594
1671
|
});
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1672
|
+
|
|
1673
|
+
if (isFederatedJwt) {
|
|
1674
|
+
// 1) signed federated API URL must be THIS server
|
|
1675
|
+
if (
|
|
1676
|
+
normalizeUrlWithoutPort(federatedIssuerUrl) !== normalizedOwnSubjectUrl
|
|
1677
|
+
) {
|
|
1678
|
+
logger.warn("Token validation failed - Invalid federated issuer URL", {
|
|
1679
|
+
component: "JwtAuth",
|
|
1680
|
+
method: "validate_jwt_token_be",
|
|
1681
|
+
requestId,
|
|
1682
|
+
federatedIssuerUrl,
|
|
1683
|
+
expectedFederatedIssuer: rodit.metadata.subjectuniqueidentifier_url,
|
|
1684
|
+
});
|
|
1685
|
+
throw new Error("Error 005: Invalid federated issuer");
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// 2) iss must be the login client's home API (from on-chain RODiT via sub)
|
|
1689
|
+
const loginClientRoditId = extractLoginPeerRoditIdFromSub(payload.sub);
|
|
1690
|
+
const loginClientRodit = loginClientRoditId
|
|
1691
|
+
? await nearorg_rpc_tokenfromroditid(loginClientRoditId)
|
|
1692
|
+
: null;
|
|
1693
|
+
const expectedClientIssuer =
|
|
1694
|
+
loginClientRodit?.metadata?.subjectuniqueidentifier_url;
|
|
1695
|
+
|
|
1696
|
+
if (
|
|
1697
|
+
!expectedClientIssuer ||
|
|
1698
|
+
normalizedTokenIssuer !==
|
|
1699
|
+
normalizeUrlWithoutPort(expectedClientIssuer)
|
|
1700
|
+
) {
|
|
1701
|
+
logger.warn("Token validation failed - Invalid issuer for federated JWT", {
|
|
1702
|
+
component: "JwtAuth",
|
|
1703
|
+
method: "validate_jwt_token_be",
|
|
1704
|
+
requestId,
|
|
1705
|
+
tokenIssuer: payload.iss,
|
|
1706
|
+
expectedClientIssuer,
|
|
1707
|
+
loginClientRoditId,
|
|
1708
|
+
});
|
|
1709
|
+
throw new Error("Error 005: Invalid issuer");
|
|
1710
|
+
}
|
|
1711
|
+
} else if (normalizedTokenIssuer !== normalizedOwnSubjectUrl) {
|
|
1712
|
+
// same-API / 9.12 tokens: iss must equal receiving server URL
|
|
1598
1713
|
logger.warn("Token validation failed - Invalid issuer", {
|
|
1599
1714
|
component: "JwtAuth",
|
|
1600
1715
|
method: "validate_jwt_token_be",
|
|
@@ -1602,15 +1717,16 @@ function resolveCredentialExpirationUnix(now, sessionExpiration, own_rodit) {
|
|
|
1602
1717
|
tokenIssuer: payload.iss,
|
|
1603
1718
|
expectedIssuer: rodit.metadata.subjectuniqueidentifier_url,
|
|
1604
1719
|
normalizedTokenIssuer,
|
|
1605
|
-
|
|
1720
|
+
normalizedOwnSubjectUrl,
|
|
1606
1721
|
roditId: rodit.token_id,
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
issuerHasProtocol: payload.iss?.startsWith(
|
|
1611
|
-
expectedHasProtocol:
|
|
1722
|
+
issuerHasTrailingSlash: payload.iss?.endsWith("/"),
|
|
1723
|
+
expectedHasTrailingSlash:
|
|
1724
|
+
rodit.metadata.subjectuniqueidentifier_url?.endsWith("/"),
|
|
1725
|
+
issuerHasProtocol: payload.iss?.startsWith("http"),
|
|
1726
|
+
expectedHasProtocol:
|
|
1727
|
+
rodit.metadata.subjectuniqueidentifier_url?.startsWith("http"),
|
|
1612
1728
|
});
|
|
1613
|
-
|
|
1729
|
+
|
|
1614
1730
|
throw new Error("Error 005: Invalid issuer");
|
|
1615
1731
|
}
|
|
1616
1732
|
|
|
@@ -2590,4 +2706,8 @@ module.exports = {
|
|
|
2590
2706
|
parseRoditJwtDurationSeconds,
|
|
2591
2707
|
resolveSessionExpirationUnix,
|
|
2592
2708
|
resolveCredentialExpirationUnix,
|
|
2709
|
+
normalizeUrlWithoutPort,
|
|
2710
|
+
isNonEmptyUrlClaim,
|
|
2711
|
+
isFederatedRoditLogin,
|
|
2712
|
+
validateFederatedLoginTarget,
|
|
2593
2713
|
};
|
|
@@ -14,7 +14,8 @@ const nacl = require("tweetnacl");
|
|
|
14
14
|
const {
|
|
15
15
|
validate_jwt_token_be,
|
|
16
16
|
generate_jwt_token,
|
|
17
|
-
|
|
17
|
+
validateFederatedLoginTarget,
|
|
18
|
+
normalizeUrlWithoutPort,
|
|
18
19
|
} = require("../auth/tokenservice");
|
|
19
20
|
// Import specific functions from authentication.js to avoid circular dependencies
|
|
20
21
|
// Import specific functions from authentication.js to avoid circular dependencies
|
|
@@ -1879,6 +1880,7 @@ async function login_portal(config_own_rodit, port, options = {}) {
|
|
|
1879
1880
|
* @param {Object} config_own_rodit - Configuration object containing own_rodit and private key
|
|
1880
1881
|
* @param {Object} [options] - Optional settings
|
|
1881
1882
|
* @param {string} [options.loginPath] - HTTP path (default /api/login)
|
|
1883
|
+
* @param {string} [options.apiEndpoint] - Federated API base URL to log into (defaults to own subjectuniqueidentifier_url)
|
|
1882
1884
|
* @param {number} [options.timestamp] - Unix seconds used for signature generation (if omitted, fetched from peer /api/login/timestamp)
|
|
1883
1885
|
* @param {string} [options.accountId] - Explicit NEAR account for outbound login when token id absent
|
|
1884
1886
|
* @param {string} [options.timestampPath] - Timestamp endpoint path (default /api/login/timestamp)
|
|
@@ -1931,7 +1933,9 @@ async function login_portal(config_own_rodit, port, options = {}) {
|
|
|
1931
1933
|
return { error: "Error 0111: Client configuration not initialized" };
|
|
1932
1934
|
}
|
|
1933
1935
|
|
|
1934
|
-
const apiendpoint =
|
|
1936
|
+
const apiendpoint =
|
|
1937
|
+
options.apiEndpoint ??
|
|
1938
|
+
config_own_rodit.own_rodit?.metadata?.subjectuniqueidentifier_url;
|
|
1935
1939
|
const loginPath =
|
|
1936
1940
|
options.loginPath ??
|
|
1937
1941
|
config_own_rodit.login_rodit_path ??
|
|
@@ -1944,7 +1948,16 @@ async function login_portal(config_own_rodit, port, options = {}) {
|
|
|
1944
1948
|
requestId,
|
|
1945
1949
|
apiEndpoint: apiendpoint,
|
|
1946
1950
|
loginUrl,
|
|
1947
|
-
|
|
1951
|
+
federatedLogin:
|
|
1952
|
+
normalizeUrlWithoutPort(apiendpoint) !==
|
|
1953
|
+
normalizeUrlWithoutPort(
|
|
1954
|
+
config_own_rodit.own_rodit?.metadata?.subjectuniqueidentifier_url
|
|
1955
|
+
),
|
|
1956
|
+
source: options.apiEndpoint
|
|
1957
|
+
? "options.apiEndpoint"
|
|
1958
|
+
: config_own_rodit.own_rodit?.metadata?.subjectuniqueidentifier_url
|
|
1959
|
+
? "metadata"
|
|
1960
|
+
: "config",
|
|
1948
1961
|
});
|
|
1949
1962
|
|
|
1950
1963
|
const roditid = normalizeOptionalLoginString(own_rodit?.token_id);
|
|
@@ -2158,6 +2171,60 @@ async function login_portal(config_own_rodit, port, options = {}) {
|
|
|
2158
2171
|
};
|
|
2159
2172
|
}
|
|
2160
2173
|
|
|
2174
|
+
const federatedCheck = validateFederatedLoginTarget(
|
|
2175
|
+
validationResult.payload,
|
|
2176
|
+
apiendpoint,
|
|
2177
|
+
config_own_rodit.own_rodit?.metadata?.subjectuniqueidentifier_url
|
|
2178
|
+
);
|
|
2179
|
+
|
|
2180
|
+
if (!federatedCheck.ok) {
|
|
2181
|
+
const duration = Date.now() - startTime;
|
|
2182
|
+
|
|
2183
|
+
logger.error("Federated login issuer check failed", {
|
|
2184
|
+
component: "AuthenticationService",
|
|
2185
|
+
method,
|
|
2186
|
+
requestId,
|
|
2187
|
+
duration,
|
|
2188
|
+
errorCode: federatedCheck.errorCode,
|
|
2189
|
+
errorMessage: federatedCheck.errorMessage,
|
|
2190
|
+
intendedApiEndpoint: apiendpoint,
|
|
2191
|
+
jwtIss: validationResult.payload?.iss,
|
|
2192
|
+
jwtFederatedIssuer:
|
|
2193
|
+
validationResult.payload?.rodit_subjectuniqueidentifier_url,
|
|
2194
|
+
});
|
|
2195
|
+
|
|
2196
|
+
logger.metric("login_duration_ms", duration, {
|
|
2197
|
+
component: "AuthenticationService",
|
|
2198
|
+
success: false,
|
|
2199
|
+
error: federatedCheck.errorCode,
|
|
2200
|
+
});
|
|
2201
|
+
logger.metric("login_errors_total", 1, {
|
|
2202
|
+
component: "AuthenticationService",
|
|
2203
|
+
error: federatedCheck.errorCode,
|
|
2204
|
+
});
|
|
2205
|
+
|
|
2206
|
+
return {
|
|
2207
|
+
error:
|
|
2208
|
+
federatedCheck.errorMessage ||
|
|
2209
|
+
"Federated login issuer verification failed",
|
|
2210
|
+
errorCode: federatedCheck.errorCode,
|
|
2211
|
+
failureReason: federatedCheck.errorCode,
|
|
2212
|
+
requestId,
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
if (federatedCheck.federated) {
|
|
2217
|
+
logger.info("Federated login issuer verified", {
|
|
2218
|
+
component: "AuthenticationService",
|
|
2219
|
+
method,
|
|
2220
|
+
requestId,
|
|
2221
|
+
intendedApiEndpoint: apiendpoint,
|
|
2222
|
+
clientHomeIssuer: validationResult.payload?.iss,
|
|
2223
|
+
federatedIssuer:
|
|
2224
|
+
validationResult.payload?.rodit_subjectuniqueidentifier_url,
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2161
2228
|
const peer_base64url_jwk_public_key = Buffer.from(peer_rodit.owner_id, "hex").toString("base64url");
|
|
2162
2229
|
await stateManager.setPeerBase64urlJwkPublicKey(peer_base64url_jwk_public_key);
|
|
2163
2230
|
// Inbound webhooks are verified against the key each webhook advertises
|