@openverifiable/connector-bluesky 1.0.1 → 1.0.2
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/lib/client-assertion.d.ts +8 -2
- package/lib/client-assertion.d.ts.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +58 -3
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client Assertion Generation for private_key_jwt
|
|
3
3
|
*
|
|
4
|
-
* Generates JWT client assertion for OAuth
|
|
4
|
+
* Generates JWT client assertion for OAuth authentication
|
|
5
|
+
* Used for both PAR (Pushed Authorization Request) and token endpoint requests
|
|
5
6
|
* RFC 7523: https://datatracker.ietf.org/doc/html/rfc7523
|
|
6
7
|
*/
|
|
7
8
|
import type { BlueskyConfig } from './types.js';
|
|
@@ -14,6 +15,11 @@ import type { BlueskyConfig } from './types.js';
|
|
|
14
15
|
*
|
|
15
16
|
* For now, we'll support both approaches - if privateKeyJwk is in config, use it.
|
|
16
17
|
* Otherwise, the server should provide an endpoint to generate assertions.
|
|
18
|
+
*
|
|
19
|
+
* @param clientId - The OAuth client identifier
|
|
20
|
+
* @param audience - The audience URL (PAR endpoint or token endpoint)
|
|
21
|
+
* @param config - Bluesky connector configuration
|
|
22
|
+
* @returns JWT client assertion string, or null if private key is not available
|
|
17
23
|
*/
|
|
18
|
-
export declare function generateClientAssertion(clientId: string,
|
|
24
|
+
export declare function generateClientAssertion(clientId: string, audience: string, config: BlueskyConfig): Promise<string | null>;
|
|
19
25
|
//# sourceMappingURL=client-assertion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-assertion.d.ts","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client-assertion.d.ts","sourceRoot":"","sources":["../src/client-assertion.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB"}
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAIV,eAAe,EACf,eAAe,EAChB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAIV,eAAe,EACf,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAupB9B;;GAEG;AACH,QAAA,MAAM,sBAAsB,EAAE,eAAe,CAAC,eAAe,CAW5D,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -619,7 +619,8 @@ async function fetchAuthorizationServerMetadataFromUrl(authServerUrl) {
|
|
|
619
619
|
/**
|
|
620
620
|
* Client Assertion Generation for private_key_jwt
|
|
621
621
|
*
|
|
622
|
-
* Generates JWT client assertion for OAuth
|
|
622
|
+
* Generates JWT client assertion for OAuth authentication
|
|
623
|
+
* Used for both PAR (Pushed Authorization Request) and token endpoint requests
|
|
623
624
|
* RFC 7523: https://datatracker.ietf.org/doc/html/rfc7523
|
|
624
625
|
*/
|
|
625
626
|
/**
|
|
@@ -631,8 +632,13 @@ async function fetchAuthorizationServerMetadataFromUrl(authServerUrl) {
|
|
|
631
632
|
*
|
|
632
633
|
* For now, we'll support both approaches - if privateKeyJwk is in config, use it.
|
|
633
634
|
* Otherwise, the server should provide an endpoint to generate assertions.
|
|
635
|
+
*
|
|
636
|
+
* @param clientId - The OAuth client identifier
|
|
637
|
+
* @param audience - The audience URL (PAR endpoint or token endpoint)
|
|
638
|
+
* @param config - Bluesky connector configuration
|
|
639
|
+
* @returns JWT client assertion string, or null if private key is not available
|
|
634
640
|
*/
|
|
635
|
-
async function generateClientAssertion(clientId,
|
|
641
|
+
async function generateClientAssertion(clientId, audience, config) {
|
|
636
642
|
// Check if private key is available in config (for server-side connectors)
|
|
637
643
|
// In production, this would come from Vault via a server endpoint
|
|
638
644
|
const privateKeyJwkStr = config.privateKeyJwk;
|
|
@@ -649,7 +655,7 @@ async function generateClientAssertion(clientId, tokenEndpoint, config) {
|
|
|
649
655
|
const jwt = new SignJWT({
|
|
650
656
|
iss: clientId,
|
|
651
657
|
sub: clientId,
|
|
652
|
-
aud:
|
|
658
|
+
aud: audience,
|
|
653
659
|
jti,
|
|
654
660
|
exp: now + 600,
|
|
655
661
|
iat: now,
|
|
@@ -954,6 +960,55 @@ const getAuthorizationUri = (getConfig) => async ({ state, redirectUri, ...rest
|
|
|
954
960
|
code_challenge_method: pkce.codeChallengeMethod,
|
|
955
961
|
...('login_hint' in rest && rest.login_hint ? { login_hint: String(rest.login_hint) } : {}),
|
|
956
962
|
});
|
|
963
|
+
// Add client assertion for confidential clients (required for PAR)
|
|
964
|
+
if (validatedConfig.tokenEndpointAuthMethod === 'private_key_jwt') {
|
|
965
|
+
try {
|
|
966
|
+
const clientAssertion = await generateClientAssertion(effectiveClientId, authServerMetadata.pushed_authorization_request_endpoint, validatedConfig);
|
|
967
|
+
if (clientAssertion) {
|
|
968
|
+
parParams.append('client_assertion', clientAssertion);
|
|
969
|
+
parParams.append('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
// Fallback to assertion endpoint
|
|
973
|
+
const assertionEndpoint = config.assertionEndpoint;
|
|
974
|
+
if (assertionEndpoint) {
|
|
975
|
+
const assertionResponse = await got.post(assertionEndpoint, {
|
|
976
|
+
json: {
|
|
977
|
+
clientId: effectiveClientId,
|
|
978
|
+
tokenEndpoint: authServerMetadata.pushed_authorization_request_endpoint
|
|
979
|
+
},
|
|
980
|
+
headers: {
|
|
981
|
+
'X-API-Key': config.assertionApiKey || '',
|
|
982
|
+
},
|
|
983
|
+
timeout: { request: defaultTimeout },
|
|
984
|
+
});
|
|
985
|
+
const assertionData = parseJson(assertionResponse.body);
|
|
986
|
+
if (assertionData?.client_assertion) {
|
|
987
|
+
parParams.append('client_assertion', assertionData.client_assertion);
|
|
988
|
+
parParams.append('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, {
|
|
992
|
+
error: 'Client assertion required for PAR but could not be generated',
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, {
|
|
998
|
+
error: 'Client assertion required for PAR. Provide privateKeyJwk or assertionEndpoint.',
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
catch (error) {
|
|
1004
|
+
if (error instanceof ConnectorError) {
|
|
1005
|
+
throw error;
|
|
1006
|
+
}
|
|
1007
|
+
throw new ConnectorError(ConnectorErrorCodes.General, {
|
|
1008
|
+
error: `Failed to generate client assertion for PAR: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
957
1012
|
const { requestUri, nonce } = await makePARRequest(authServerMetadata.pushed_authorization_request_endpoint, parParams, dpopKeyPair);
|
|
958
1013
|
// Store PKCE verifier and DPoP key pair in state store
|
|
959
1014
|
// Export DPoP keypair as JWK for storage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openverifiable/connector-bluesky",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Bluesky/AT Protocol OAuth connector for LogTo with PAR, PKCE, and DPoP support",
|
|
5
5
|
"author": "OpenVerifiable (https://github.com/openverifiable)",
|
|
6
6
|
"homepage": "https://openverifiable.org",
|