@commercetools/connect-payments-sdk 0.0.3 → 0.0.4

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/api/handlers/config.handler.d.ts +1 -1
  3. package/dist/api/handlers/status.handler.d.ts +9 -1
  4. package/dist/api/handlers/types/handler.type.d.ts +2 -2
  5. package/dist/api/hooks/jwt-auth.hook.d.ts +16 -0
  6. package/dist/api/hooks/jwt-auth.hook.js +22 -0
  7. package/dist/api/hooks/oauth2-auth.hook.d.ts +16 -0
  8. package/dist/api/hooks/oauth2-auth.hook.js +22 -0
  9. package/dist/api/hooks/types/hook.type.d.ts +3 -0
  10. package/dist/api/index.d.ts +2 -0
  11. package/dist/api/index.js +2 -0
  12. package/dist/errorx/errorx.d.ts +1 -1
  13. package/dist/errorx/errorx.js +3 -3
  14. package/dist/index.d.ts +6 -2
  15. package/dist/index.js +25 -1
  16. package/dist/security/authn/authns.d.ts +26 -1
  17. package/dist/security/authn/authns.js +64 -1
  18. package/dist/security/authn/bearer-utils.d.ts +1 -0
  19. package/dist/security/authn/bearer-utils.js +19 -0
  20. package/dist/security/authn/jwt-authn-manager.d.ts +12 -0
  21. package/dist/security/authn/jwt-authn-manager.js +33 -0
  22. package/dist/security/authn/oauth2-authn-manager.d.ts +17 -0
  23. package/dist/security/authn/oauth2-authn-manager.js +65 -0
  24. package/dist/security/authn/session-authn-manager.js +1 -1
  25. package/dist/security/authn/types/authn.type.d.ts +11 -2
  26. package/dist/security/index.d.ts +5 -1
  27. package/dist/security/index.js +5 -1
  28. package/dist/security/services/jwt.service.d.ts +10 -0
  29. package/dist/security/services/jwt.service.js +40 -0
  30. package/dist/security/services/oauth2.service.d.ts +9 -0
  31. package/dist/security/services/oauth2.service.js +40 -0
  32. package/dist/security/services/types/jwt.type.d.ts +5 -0
  33. package/dist/security/services/types/jwt.type.js +2 -0
  34. package/dist/security/services/types/oauth2.type.d.ts +14 -0
  35. package/dist/security/services/types/oauth2.type.js +2 -0
  36. package/package.json +4 -2
  37. package/.github/workflows/ci.yml +0 -34
  38. package/.github/workflows/release.yml +0 -46
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @commercetools/connect-payments-sdk
2
2
 
3
+ ## 0.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - ab6200f: Support jwt, oauth2 authentication and support for authority based authorization
8
+
3
9
  ## 0.0.3
4
10
 
5
11
  ### Patch Changes
@@ -1,4 +1,4 @@
1
1
  import { HandlerResponse } from './types/handler.type';
2
2
  export declare const configHandler: (options: {
3
3
  configuration: () => Promise<object> | object;
4
- }) => () => Promise<HandlerResponse>;
4
+ }) => () => Promise<HandlerResponse<object>>;
@@ -1,5 +1,12 @@
1
1
  import { CommercetoolsAuthorizationService } from '../../commercetools';
2
2
  import { HandlerResponse } from './types/handler.type';
3
+ type HealthCheckStatus = {
4
+ status: 'OK' | 'Partially Available' | 'Unavailable';
5
+ timestamp: string;
6
+ checks: HealthCheckResult[];
7
+ version: string;
8
+ metadata?: object;
9
+ };
3
10
  export type HealthCheckResult = {
4
11
  name: string;
5
12
  status: 'UP' | 'DOWN';
@@ -10,7 +17,7 @@ export declare const statusHandler: (options: {
10
17
  timeout: number;
11
18
  checks: HealthCheck[];
12
19
  metadataFn?: () => Promise<object> | object;
13
- }) => () => Promise<HandlerResponse>;
20
+ }) => () => Promise<HandlerResponse<HealthCheckStatus>>;
14
21
  /**
15
22
  * Check if CoCo permissions are available
16
23
  * @param opts
@@ -21,3 +28,4 @@ export declare const healthCheckCommercetoolsPermissions: (opts: {
21
28
  projectKey: string;
22
29
  requiredPermissions: string[];
23
30
  }) => () => Promise<HealthCheckResult>;
31
+ export {};
@@ -1,5 +1,5 @@
1
- export type HandlerResponse = {
1
+ export type HandlerResponse<T> = {
2
2
  status: number;
3
- body?: object;
3
+ body: T;
4
4
  headers?: object;
5
5
  };
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" />
2
+ import { IncomingHttpHeaders } from 'node:http';
3
+ import { JWTAuthenticationManager } from '../../security/authn/jwt-authn-manager';
4
+ import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
5
+ import { AuthenticationHook } from './types/hook.type';
6
+ export declare class JWTAuthenticationHook implements AuthenticationHook {
7
+ private authenticationManager;
8
+ private contextProvider;
9
+ constructor(opts: {
10
+ authenticationManager: JWTAuthenticationManager;
11
+ contextProvider: ContextProvider<RequestContextData>;
12
+ });
13
+ authenticate(): (request: {
14
+ headers: IncomingHttpHeaders;
15
+ }) => Promise<void>;
16
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JWTAuthenticationHook = void 0;
4
+ const security_1 = require("../../security");
5
+ class JWTAuthenticationHook {
6
+ authenticationManager;
7
+ contextProvider;
8
+ constructor(opts) {
9
+ this.authenticationManager = opts.authenticationManager;
10
+ this.contextProvider = opts.contextProvider;
11
+ }
12
+ authenticate() {
13
+ return async (request) => {
14
+ const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
15
+ const authn = await this.authenticationManager.authenticate(authorizationHeader);
16
+ this.contextProvider.updateContextData({
17
+ authentication: authn,
18
+ });
19
+ };
20
+ }
21
+ }
22
+ exports.JWTAuthenticationHook = JWTAuthenticationHook;
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" />
2
+ import { IncomingHttpHeaders } from 'node:http';
3
+ import { Oauth2AuthenticationManager } from '../../security/authn/oauth2-authn-manager';
4
+ import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
5
+ import { AuthenticationHook } from './types/hook.type';
6
+ export declare class Oauth2AuthenticationHook implements AuthenticationHook {
7
+ private authenticationManager;
8
+ private contextProvider;
9
+ constructor(opts: {
10
+ authenticationManager: Oauth2AuthenticationManager;
11
+ contextProvider: ContextProvider<RequestContextData>;
12
+ });
13
+ authenticate(): (request: {
14
+ headers: IncomingHttpHeaders;
15
+ }) => Promise<void>;
16
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Oauth2AuthenticationHook = void 0;
4
+ const security_1 = require("../../security");
5
+ class Oauth2AuthenticationHook {
6
+ authenticationManager;
7
+ contextProvider;
8
+ constructor(opts) {
9
+ this.authenticationManager = opts.authenticationManager;
10
+ this.contextProvider = opts.contextProvider;
11
+ }
12
+ authenticate() {
13
+ return async (request) => {
14
+ const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
15
+ const authn = await this.authenticationManager.authenticate(authorizationHeader);
16
+ this.contextProvider.updateContextData({
17
+ authentication: authn,
18
+ });
19
+ };
20
+ }
21
+ }
22
+ exports.Oauth2AuthenticationHook = Oauth2AuthenticationHook;
@@ -5,3 +5,6 @@ export interface AuthenticationHook {
5
5
  headers: IncomingHttpHeaders;
6
6
  }) => Promise<void>;
7
7
  }
8
+ export interface AuthorizationHook {
9
+ authorize(...authorities: string[]): () => Promise<void>;
10
+ }
@@ -2,5 +2,7 @@ export * from './context/request-context.provider';
2
2
  export * from './context/types/request-context.type';
3
3
  export * from './handlers/config.handler';
4
4
  export * from './handlers/status.handler';
5
+ export * from './hooks/jwt-auth.hook';
6
+ export * from './hooks/oauth2-auth.hook';
5
7
  export * from './hooks/session-auth.hook';
6
8
  export * from './hooks/types/hook.type';
package/dist/api/index.js CHANGED
@@ -18,5 +18,7 @@ __exportStar(require("./context/request-context.provider"), exports);
18
18
  __exportStar(require("./context/types/request-context.type"), exports);
19
19
  __exportStar(require("./handlers/config.handler"), exports);
20
20
  __exportStar(require("./handlers/status.handler"), exports);
21
+ __exportStar(require("./hooks/jwt-auth.hook"), exports);
22
+ __exportStar(require("./hooks/oauth2-auth.hook"), exports);
21
23
  __exportStar(require("./hooks/session-auth.hook"), exports);
22
24
  __exportStar(require("./hooks/types/hook.type"), exports);
@@ -44,7 +44,7 @@ export declare class MultiErrorx extends Error {
44
44
  * }
45
45
  */
46
46
  export declare class ErrorAuthErrorResponse extends Errorx {
47
- constructor(additionalOpts?: ErrorxAdditionalOpts);
47
+ constructor(message?: string, additionalOpts?: ErrorxAdditionalOpts, code?: string);
48
48
  }
49
49
  /**
50
50
  * General (https://docs.commercetools.com/api/errors#general)
@@ -59,11 +59,11 @@ exports.MultiErrorx = MultiErrorx;
59
59
  * }
60
60
  */
61
61
  class ErrorAuthErrorResponse extends Errorx {
62
- constructor(additionalOpts) {
62
+ constructor(message, additionalOpts, code) {
63
63
  super({
64
- code: 'AuthErrorResponse',
64
+ code: code || 'invalid_token',
65
65
  httpErrorStatus: 401,
66
- message: 'Authentication error.',
66
+ message: message || 'Authentication error.',
67
67
  ...additionalOpts,
68
68
  });
69
69
  }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { RequestContextData, RequestContextProvider, SessionAuthenticationHook } from './api';
1
+ import { JWTAuthenticationHook, Oauth2AuthenticationHook, RequestContextData, RequestContextProvider, SessionAuthenticationHook } from './api';
2
2
  import { DefaultCommercetoolsAPI } from './commercetools/api/root-api';
3
+ import { DefaultAuthorizationService } from './commercetools/services/ct-authorization.service';
3
4
  import { DefaultCartService } from './commercetools/services/ct-cart.service';
4
5
  import { DefaultPaymentService } from './commercetools/services/ct-payment.service';
5
- import { DefaultAuthorizationService } from './commercetools/services/ct-authorization.service';
6
6
  import { Logger } from './logger';
7
7
  export * from './api';
8
8
  export * from './commercetools';
@@ -13,9 +13,11 @@ export declare const setupPaymentSDK: (opts: {
13
13
  authUrl: string;
14
14
  apiUrl: string;
15
15
  sessionUrl: string;
16
+ jwksUrl: string;
16
17
  clientId: string;
17
18
  clientSecret: string;
18
19
  projectKey: string;
20
+ jwtIssuer: string;
19
21
  getContextFn: () => RequestContextData;
20
22
  updateContextFn: (ctx: Partial<RequestContextData>) => void;
21
23
  logger?: Logger | undefined;
@@ -26,4 +28,6 @@ export declare const setupPaymentSDK: (opts: {
26
28
  ctAuthorizationService: DefaultAuthorizationService;
27
29
  contextProvider: RequestContextProvider;
28
30
  sessionAuthHookFn: SessionAuthenticationHook;
31
+ jwtAuthHookFn: JWTAuthenticationHook;
32
+ oauth2AuthHookFn: Oauth2AuthenticationHook;
29
33
  };
package/dist/index.js CHANGED
@@ -17,9 +17,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.setupPaymentSDK = void 0;
18
18
  const api_1 = require("./api");
19
19
  const root_api_1 = require("./commercetools/api/root-api");
20
+ const ct_authorization_service_1 = require("./commercetools/services/ct-authorization.service");
20
21
  const ct_cart_service_1 = require("./commercetools/services/ct-cart.service");
21
22
  const ct_payment_service_1 = require("./commercetools/services/ct-payment.service");
22
- const ct_authorization_service_1 = require("./commercetools/services/ct-authorization.service");
23
23
  const ct_session_service_1 = require("./commercetools/services/ct-session.service");
24
24
  const base_decorator_1 = require("./fetch/decorators/base.decorator");
25
25
  const monitoring_decorator_1 = require("./fetch/decorators/monitoring.decorator");
@@ -57,13 +57,35 @@ const setupPaymentSDK = (opts) => {
57
57
  sessionUrl: opts.sessionUrl,
58
58
  projectKey: opts.projectKey,
59
59
  });
60
+ const oauth2Service = new security_1.DefaultOauth2Service();
61
+ const jwtService = new security_1.DefaultJWTService({
62
+ jwksUrl: opts.jwksUrl,
63
+ });
60
64
  const sessionAuthenticationManager = new security_1.SessionAuthenticationManager({
61
65
  sessionService,
62
66
  });
67
+ const oauth2AuthenticationManager = new security_1.Oauth2AuthenticationManager({
68
+ oauth2Service,
69
+ clientId: opts.clientId,
70
+ clientSecret: opts.clientSecret,
71
+ authUrl: opts.authUrl,
72
+ });
73
+ const jwtAuthenticationManager = new security_1.JWTAuthenticationManager({
74
+ jwtService,
75
+ iss: opts.jwtIssuer,
76
+ });
63
77
  const sessionAuthHookFn = new api_1.SessionAuthenticationHook({
64
78
  authenticationManager: sessionAuthenticationManager,
65
79
  contextProvider,
66
80
  });
81
+ const jwtAuthHookFn = new api_1.JWTAuthenticationHook({
82
+ authenticationManager: jwtAuthenticationManager,
83
+ contextProvider,
84
+ });
85
+ const oauth2AuthHookFn = new api_1.Oauth2AuthenticationHook({
86
+ authenticationManager: oauth2AuthenticationManager,
87
+ contextProvider,
88
+ });
67
89
  return {
68
90
  ctAPI,
69
91
  ctCartService,
@@ -71,6 +93,8 @@ const setupPaymentSDK = (opts) => {
71
93
  ctAuthorizationService,
72
94
  contextProvider,
73
95
  sessionAuthHookFn,
96
+ jwtAuthHookFn,
97
+ oauth2AuthHookFn,
74
98
  };
75
99
  };
76
100
  exports.setupPaymentSDK = setupPaymentSDK;
@@ -1,4 +1,4 @@
1
- import { Authentication, HeaderPrincipal, SessionPrincipal } from './types/authn.type';
1
+ import { Authentication, HeaderPrincipal, JWTPrincipal, Oauth2Principal, SessionPrincipal } from './types/authn.type';
2
2
  export declare class SessionAuthentication implements Authentication<SessionPrincipal, string> {
3
3
  private principal;
4
4
  private authorities;
@@ -22,3 +22,28 @@ export declare class HeaderBasedAuthentication implements Authentication<HeaderP
22
22
  getPrincipal(): HeaderPrincipal;
23
23
  isAuthenticated(): boolean;
24
24
  }
25
+ export declare class Oauth2Authentication implements Authentication<Oauth2Principal, string> {
26
+ private principal;
27
+ private authorities;
28
+ private authenticated;
29
+ private accessToken;
30
+ constructor(accessToken: string, principal: Oauth2Principal);
31
+ hasPrincipal(): boolean;
32
+ getAuthorities(): string[];
33
+ hasCredentials(): boolean;
34
+ getPrincipal(): Oauth2Principal;
35
+ getCredentials(): string;
36
+ isAuthenticated(): boolean;
37
+ }
38
+ export declare class JWTAuthentication implements Authentication<JWTPrincipal, string> {
39
+ private principal;
40
+ private authenticated;
41
+ private jwt;
42
+ constructor(jwt: string, principal: JWTPrincipal);
43
+ hasPrincipal(): boolean;
44
+ getAuthorities(): string[];
45
+ hasCredentials(): boolean;
46
+ getPrincipal(): JWTPrincipal;
47
+ getCredentials(): string;
48
+ isAuthenticated(): boolean;
49
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HeaderBasedAuthentication = exports.SessionAuthentication = void 0;
3
+ exports.JWTAuthentication = exports.Oauth2Authentication = exports.HeaderBasedAuthentication = exports.SessionAuthentication = void 0;
4
4
  class SessionAuthentication {
5
5
  principal;
6
6
  authorities;
@@ -58,3 +58,66 @@ class HeaderBasedAuthentication {
58
58
  }
59
59
  }
60
60
  exports.HeaderBasedAuthentication = HeaderBasedAuthentication;
61
+ class Oauth2Authentication {
62
+ principal;
63
+ authorities;
64
+ authenticated;
65
+ accessToken;
66
+ constructor(accessToken, principal) {
67
+ this.principal = principal;
68
+ this.authorities = principal.scope
69
+ .split(' ')
70
+ .map((scope) => scope.split(':')[0])
71
+ .filter((scope) => scope !== '');
72
+ this.authenticated = true;
73
+ this.accessToken = accessToken;
74
+ }
75
+ hasPrincipal() {
76
+ return this.getPrincipal() !== undefined;
77
+ }
78
+ getAuthorities() {
79
+ return this.authorities;
80
+ }
81
+ hasCredentials() {
82
+ return this.getCredentials() !== undefined;
83
+ }
84
+ getPrincipal() {
85
+ return this.principal;
86
+ }
87
+ getCredentials() {
88
+ return this.accessToken;
89
+ }
90
+ isAuthenticated() {
91
+ return this.authenticated;
92
+ }
93
+ }
94
+ exports.Oauth2Authentication = Oauth2Authentication;
95
+ class JWTAuthentication {
96
+ principal;
97
+ authenticated;
98
+ jwt;
99
+ constructor(jwt, principal) {
100
+ this.principal = principal;
101
+ this.authenticated = true;
102
+ this.jwt = jwt;
103
+ }
104
+ hasPrincipal() {
105
+ return this.getPrincipal() !== undefined;
106
+ }
107
+ getAuthorities() {
108
+ return [];
109
+ }
110
+ hasCredentials() {
111
+ return this.getCredentials() !== undefined;
112
+ }
113
+ getPrincipal() {
114
+ return this.principal;
115
+ }
116
+ getCredentials() {
117
+ return this.jwt;
118
+ }
119
+ isAuthenticated() {
120
+ return this.authenticated;
121
+ }
122
+ }
123
+ exports.JWTAuthentication = JWTAuthentication;
@@ -0,0 +1 @@
1
+ export declare const validateBearerAuthorization: (authorization: string | undefined) => string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateBearerAuthorization = void 0;
4
+ const errorx_1 = require("../../errorx");
5
+ const validateBearerAuthorization = (authorization) => {
6
+ if (!authorization) {
7
+ throw new errorx_1.ErrorAuthErrorResponse('This endpoint requires the authorization header.', {
8
+ skipLog: true,
9
+ }, 'access_denied');
10
+ }
11
+ const authorizationParts = authorization.split(' ');
12
+ if (authorizationParts.length !== 2 || authorizationParts[0] !== 'Bearer') {
13
+ throw new errorx_1.ErrorAuthErrorResponse(`Authorization header must have the format 'Bearer <token>'`, {
14
+ skipLog: true,
15
+ }, 'invalid_request');
16
+ }
17
+ return authorizationParts[1];
18
+ };
19
+ exports.validateBearerAuthorization = validateBearerAuthorization;
@@ -0,0 +1,12 @@
1
+ import { JWTService } from '../services/types/jwt.type';
2
+ import { HeaderBasedAuthentication, JWTAuthentication } from './authns';
3
+ import { AuthenticationManager } from './types/authn.type';
4
+ export declare class JWTAuthenticationManager implements AuthenticationManager {
5
+ private jwtService;
6
+ private iss;
7
+ constructor(opts: {
8
+ jwtService: JWTService;
9
+ iss: string;
10
+ });
11
+ authenticate(authentication: HeaderBasedAuthentication): Promise<JWTAuthentication>;
12
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JWTAuthenticationManager = void 0;
4
+ const errorx_1 = require("../../errorx");
5
+ const authns_1 = require("./authns");
6
+ const bearer_utils_1 = require("./bearer-utils");
7
+ class JWTAuthenticationManager {
8
+ jwtService;
9
+ iss;
10
+ constructor(opts) {
11
+ this.jwtService = opts.jwtService;
12
+ this.iss = opts.iss;
13
+ }
14
+ async authenticate(authentication) {
15
+ const principal = authentication.getPrincipal();
16
+ const token = (0, bearer_utils_1.validateBearerAuthorization)(principal.authHeader);
17
+ const decodedToken = (await this.jwtService.verify({
18
+ token,
19
+ }));
20
+ if (decodedToken.iss !== this.iss) {
21
+ throw new errorx_1.ErrorAuthErrorResponse('Issuer in the token does not match the expected issuer', {
22
+ privateFields: {
23
+ expectedIssuer: this.iss,
24
+ actualIssuer: decodedToken['iss'],
25
+ },
26
+ });
27
+ }
28
+ return new authns_1.JWTAuthentication(token, {
29
+ mcCustomerId: decodedToken['sub'],
30
+ });
31
+ }
32
+ }
33
+ exports.JWTAuthenticationManager = JWTAuthenticationManager;
@@ -0,0 +1,17 @@
1
+ import { Oauth2Service } from '../services/types/oauth2.type';
2
+ import { HeaderBasedAuthentication, Oauth2Authentication } from './authns';
3
+ import { AuthenticationManager } from './types/authn.type';
4
+ export declare class Oauth2AuthenticationManager implements AuthenticationManager {
5
+ private oauth2Service;
6
+ private clientId;
7
+ private clientSecret;
8
+ private authUrl;
9
+ constructor(opts: {
10
+ oauth2Service: Oauth2Service;
11
+ clientId: string;
12
+ clientSecret: string;
13
+ authUrl: string;
14
+ });
15
+ authenticate(authentication: HeaderBasedAuthentication): Promise<Oauth2Authentication>;
16
+ private searchPermission;
17
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Oauth2AuthenticationManager = void 0;
4
+ const errorx_1 = require("../../errorx");
5
+ const authns_1 = require("./authns");
6
+ const bearer_utils_1 = require("./bearer-utils");
7
+ class Oauth2AuthenticationManager {
8
+ oauth2Service;
9
+ clientId;
10
+ clientSecret;
11
+ authUrl;
12
+ constructor(opts) {
13
+ this.oauth2Service = opts.oauth2Service;
14
+ this.clientId = opts.clientId;
15
+ this.clientSecret = opts.clientSecret;
16
+ this.authUrl = opts.authUrl;
17
+ }
18
+ async authenticate(authentication) {
19
+ const principal = authentication.getPrincipal();
20
+ const authorizationHeader = principal.authHeader;
21
+ const token = (0, bearer_utils_1.validateBearerAuthorization)(authorizationHeader);
22
+ const tokenIntrospectionResponseData = await this.oauth2Service.introspectToken({
23
+ url: `${this.authUrl}/oauth/introspect`,
24
+ clientId: this.clientId,
25
+ clientSecret: this.clientSecret,
26
+ token,
27
+ });
28
+ if (!tokenIntrospectionResponseData.active) {
29
+ throw new errorx_1.ErrorAuthErrorResponse('invalid_token', {
30
+ skipLog: true,
31
+ });
32
+ }
33
+ const scopes = tokenIntrospectionResponseData.scope?.split(' ') ?? null;
34
+ if (!scopes) {
35
+ throw new errorx_1.ErrorAuthErrorResponse('Token has no scopes.', {
36
+ skipLog: true,
37
+ });
38
+ }
39
+ // Search for customer_id:<customer> scope
40
+ const customerPermission = this.searchPermission(scopes, 'customer_id');
41
+ // Search for anonymous_id:<anonymous> scope
42
+ const anonymousPermission = this.searchPermission(scopes, 'anonymous_id');
43
+ return new authns_1.Oauth2Authentication(token, {
44
+ scope: tokenIntrospectionResponseData.scope,
45
+ clientId: tokenIntrospectionResponseData.client_id,
46
+ customerId: customerPermission?.principal,
47
+ anonymousId: anonymousPermission?.principal,
48
+ });
49
+ }
50
+ searchPermission(scopes, ...permissions) {
51
+ for (const permission of permissions) {
52
+ // Search for customer_id:<customer> scope
53
+ const permissionIndex = scopes.findIndex((element) => element.startsWith(`${permission}`));
54
+ if (permissionIndex >= 0) {
55
+ const splitPermission = scopes[permissionIndex].split(':');
56
+ return {
57
+ permission: splitPermission[0],
58
+ principal: splitPermission[1],
59
+ };
60
+ }
61
+ }
62
+ return undefined;
63
+ }
64
+ }
65
+ exports.Oauth2AuthenticationManager = Oauth2AuthenticationManager;
@@ -18,7 +18,7 @@ class SessionAuthenticationManager {
18
18
  });
19
19
  }
20
20
  catch (e) {
21
- throw new errorx_1.ErrorAuthErrorResponse();
21
+ throw new errorx_1.ErrorAuthErrorResponse('Session is not active');
22
22
  }
23
23
  }
24
24
  }
@@ -9,10 +9,19 @@ export interface Authentication<Principal = unknown, Credentials = unknown> {
9
9
  getCredentials(): Credentials;
10
10
  isAuthenticated(): boolean;
11
11
  }
12
+ export type HeaderPrincipal = {
13
+ authHeader: string;
14
+ };
12
15
  export type SessionPrincipal = {
13
16
  cartId: string;
14
17
  allowedPaymentMethods: string[];
15
18
  };
16
- export type HeaderPrincipal = {
17
- authHeader: string;
19
+ export type Oauth2Principal = {
20
+ clientId: string;
21
+ scope: string;
22
+ customerId?: string;
23
+ anonymousId?: string;
24
+ };
25
+ export type JWTPrincipal = {
26
+ mcCustomerId?: string;
18
27
  };
@@ -1,3 +1,7 @@
1
- export * from './authn/types/authn.type';
2
1
  export * from './authn/authns';
2
+ export * from './authn/jwt-authn-manager';
3
+ export * from './authn/oauth2-authn-manager';
3
4
  export * from './authn/session-authn-manager';
5
+ export * from './authn/types/authn.type';
6
+ export * from './services/jwt.service';
7
+ export * from './services/oauth2.service';
@@ -14,6 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./authn/types/authn.type"), exports);
18
17
  __exportStar(require("./authn/authns"), exports);
18
+ __exportStar(require("./authn/jwt-authn-manager"), exports);
19
+ __exportStar(require("./authn/oauth2-authn-manager"), exports);
19
20
  __exportStar(require("./authn/session-authn-manager"), exports);
21
+ __exportStar(require("./authn/types/authn.type"), exports);
22
+ __exportStar(require("./services/jwt.service"), exports);
23
+ __exportStar(require("./services/oauth2.service"), exports);
@@ -0,0 +1,10 @@
1
+ import { JWTService } from './types/jwt.type';
2
+ export declare class DefaultJWTService implements JWTService {
3
+ private client;
4
+ constructor(opts: {
5
+ jwksUrl: string;
6
+ });
7
+ verify(opts: {
8
+ token: string | undefined;
9
+ }): Promise<unknown>;
10
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DefaultJWTService = void 0;
7
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
+ const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
9
+ const errorx_1 = require("../../errorx");
10
+ class DefaultJWTService {
11
+ client;
12
+ constructor(opts) {
13
+ this.client = (0, jwks_rsa_1.default)({
14
+ jwksUri: opts.jwksUrl,
15
+ });
16
+ }
17
+ async verify(opts) {
18
+ const getKey = (header, callback) => {
19
+ this.client.getSigningKey(header.kid, function (err, key) {
20
+ if (err) {
21
+ return callback(err);
22
+ }
23
+ const signingKey = key.getPublicKey();
24
+ callback(null, signingKey);
25
+ });
26
+ };
27
+ return new Promise((resolve, reject) => {
28
+ if (!opts.token) {
29
+ throw new errorx_1.ErrorAuthErrorResponse('Token is missing');
30
+ }
31
+ jsonwebtoken_1.default.verify(opts.token, getKey, {}, function (err, decoded) {
32
+ if (err) {
33
+ return reject(new errorx_1.ErrorAuthErrorResponse(err.message, { privateMessage: err.message, cause: err }));
34
+ }
35
+ return resolve(decoded);
36
+ });
37
+ });
38
+ }
39
+ }
40
+ exports.DefaultJWTService = DefaultJWTService;
@@ -0,0 +1,9 @@
1
+ import { Oauth2Service, TokenInfo } from './types/oauth2.type';
2
+ export declare class DefaultOauth2Service implements Oauth2Service {
3
+ introspectToken(opts: {
4
+ url: string;
5
+ clientId: string;
6
+ clientSecret: string;
7
+ token: string;
8
+ }): Promise<TokenInfo>;
9
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultOauth2Service = void 0;
4
+ const errorx_1 = require("../../errorx");
5
+ class DefaultOauth2Service {
6
+ async introspectToken(opts) {
7
+ const urlencoded = new URLSearchParams();
8
+ urlencoded.append('token', opts.token);
9
+ const tokenResponse = await fetch(opts.url, {
10
+ method: 'POST',
11
+ headers: {
12
+ 'Content-Type': 'application/x-www-form-urlencoded',
13
+ Authorization: `Basic ${btoa(opts.clientId + ':' + opts.clientSecret)}`,
14
+ },
15
+ body: urlencoded,
16
+ });
17
+ if (tokenResponse.status > 299) {
18
+ if (tokenResponse.status === 401) {
19
+ const tokenResponseJson = (await tokenResponse.json());
20
+ throw new errorx_1.ErrorAuthErrorResponse(tokenResponseJson.message, {
21
+ privateFields: {
22
+ clientId: opts.clientId,
23
+ status: tokenResponse.status,
24
+ },
25
+ skipLog: true,
26
+ }, tokenResponseJson.error);
27
+ }
28
+ throw new errorx_1.ErrorGeneral('Failed to authorize request.', {
29
+ privateMessage: 'some error happened while requesting token from coco',
30
+ privateFields: {
31
+ clientId: opts.clientId,
32
+ status: tokenResponse.status,
33
+ },
34
+ skipLog: true,
35
+ });
36
+ }
37
+ return (await tokenResponse.json());
38
+ }
39
+ }
40
+ exports.DefaultOauth2Service = DefaultOauth2Service;
@@ -0,0 +1,5 @@
1
+ export interface JWTService {
2
+ verify(opts: {
3
+ token: string | undefined;
4
+ }): Promise<unknown>;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ export type TokenInfo = {
2
+ active: boolean;
3
+ scope: string;
4
+ exp: number;
5
+ client_id: string;
6
+ };
7
+ export interface Oauth2Service {
8
+ introspectToken(opts: {
9
+ url: string;
10
+ clientId: string;
11
+ clientSecret: string;
12
+ token: string;
13
+ }): Promise<TokenInfo>;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercetools/connect-payments-sdk",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Payment SDK for commercetools payment connectors",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,6 +16,8 @@
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
18
  "@commercetools/platform-sdk": "7.2.0-alpha.4",
19
- "@commercetools/sdk-client-v2": "2.3.0"
19
+ "@commercetools/sdk-client-v2": "2.3.0",
20
+ "jsonwebtoken": "9.0.2",
21
+ "jwks-rsa": "3.1.0"
20
22
  }
21
23
  }
@@ -1,34 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- pull_request:
5
- branches: [ main ]
6
-
7
- jobs:
8
- ci:
9
- runs-on: ubuntu-latest
10
- steps:
11
- - name: Checkout Repo
12
- uses: actions/checkout@v4
13
-
14
- - name: Install Node.js
15
- uses: actions/setup-node@v3
16
- with:
17
- node-version: 20
18
-
19
- - name: Install dependencies
20
- uses: pnpm/action-setup@v2
21
- with:
22
- version: 8
23
- run_install: |
24
- - recursive: true
25
- args: [--frozen-lockfile, --strict-peer-dependencies]
26
-
27
- - name: Build
28
- run: pnpm run build
29
-
30
- - name: Static code analysis
31
- run: pnpm run lint
32
-
33
- - name: Tests
34
- run: pnpm run test
@@ -1,46 +0,0 @@
1
- name: Release
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
-
7
- jobs:
8
- publish-gpr:
9
- runs-on: ubuntu-latest
10
- steps:
11
- - name: Checkout Repo
12
- uses: actions/checkout@v4
13
-
14
- - name: Install Node.js
15
- uses: actions/setup-node@v3
16
- with:
17
- node-version: 20
18
-
19
- - name: Install dependencies
20
- uses: pnpm/action-setup@v2
21
- with:
22
- version: 8
23
- run_install: |
24
- - recursive: true
25
- args: [--frozen-lockfile, --strict-peer-dependencies]
26
-
27
- - name: Static code analysis
28
- run: pnpm run lint
29
-
30
- - name: Tests
31
- run: pnpm run test
32
-
33
- - name: Create Release Pull Request or Publish to npm
34
- id: changesets
35
- uses: changesets/action@v1
36
- with:
37
- # This expects you to have a script called release which does a build for your packages and calls changeset publish
38
- publish: pnpm run release
39
- env:
40
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
42
-
43
- - name: Create release
44
- if: steps.changesets.outputs.published == 'true'
45
- # You can do something when a publish happens.
46
- run: VERSION=$(jq '.version' package.json -r);gh release create "$VERSION" --title "$VERSION [@commercetools/connect-payments-sdk]" --notes 'Check CHANGELOG.md file.'