@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.
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Client Assertion Generation for private_key_jwt
3
3
  *
4
- * Generates JWT client assertion for OAuth token endpoint authentication
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, tokenEndpoint: string, config: BlueskyConfig): Promise<string | null>;
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;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB"}
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"}
@@ -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;AAkmB9B;;GAEG;AACH,QAAA,MAAM,sBAAsB,EAAE,eAAe,CAAC,eAAe,CAW5D,CAAC;AAEF,eAAe,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 token endpoint authentication
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, tokenEndpoint, config) {
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: tokenEndpoint,
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.1",
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",