@mcp-abap-adt/auth-providers 1.2.0 → 2.2.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/COPYING +674 -0
  3. package/LICENSE +160 -17
  4. package/README.md +401 -66
  5. package/bin/auth-authorization-code.ts +5 -3
  6. package/dist/__tests__/helpers/netHelpers.d.ts +16 -0
  7. package/dist/__tests__/helpers/netHelpers.d.ts.map +1 -1
  8. package/dist/__tests__/helpers/netHelpers.js +29 -0
  9. package/dist/__tests__/helpers/testLogger.d.ts +1 -1
  10. package/dist/__tests__/helpers/testLogger.d.ts.map +1 -1
  11. package/dist/auth/announce.d.ts +11 -0
  12. package/dist/auth/announce.d.ts.map +1 -0
  13. package/dist/auth/announce.js +19 -0
  14. package/dist/auth/browserAuth.d.ts +23 -15
  15. package/dist/auth/browserAuth.d.ts.map +1 -1
  16. package/dist/auth/browserAuth.js +25 -111
  17. package/dist/auth/callbackServer.d.ts +7 -1
  18. package/dist/auth/callbackServer.d.ts.map +1 -1
  19. package/dist/auth/callbackServer.js +31 -21
  20. package/dist/auth/deviceFlowAuth.d.ts +1 -1
  21. package/dist/auth/deviceFlowAuth.d.ts.map +1 -1
  22. package/dist/auth/oidcBrowserAuth.d.ts +2 -9
  23. package/dist/auth/oidcBrowserAuth.d.ts.map +1 -1
  24. package/dist/auth/oidcBrowserAuth.js +16 -125
  25. package/dist/auth/oidcDiscovery.d.ts +1 -1
  26. package/dist/auth/oidcDiscovery.d.ts.map +1 -1
  27. package/dist/auth/oidcToken.d.ts +1 -1
  28. package/dist/auth/oidcToken.d.ts.map +1 -1
  29. package/dist/auth/saml2Auth.d.ts +2 -9
  30. package/dist/auth/saml2Auth.d.ts.map +1 -1
  31. package/dist/auth/saml2Auth.js +10 -130
  32. package/dist/auth/saml2TokenExchange.d.ts +1 -1
  33. package/dist/auth/saml2TokenExchange.d.ts.map +1 -1
  34. package/dist/errors/TokenProviderErrors.js +6 -6
  35. package/dist/index.d.ts +6 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +21 -1
  38. package/dist/providers/AuthorizationCodeProvider.d.ts +8 -3
  39. package/dist/providers/AuthorizationCodeProvider.d.ts.map +1 -1
  40. package/dist/providers/AuthorizationCodeProvider.js +55 -44
  41. package/dist/providers/BaseTokenProvider.d.ts +2 -1
  42. package/dist/providers/BaseTokenProvider.d.ts.map +1 -1
  43. package/dist/providers/ClientCredentialsProvider.d.ts +1 -1
  44. package/dist/providers/ClientCredentialsProvider.d.ts.map +1 -1
  45. package/dist/providers/ClientCredentialsProvider.js +3 -3
  46. package/dist/providers/DeviceFlowProvider.d.ts +3 -1
  47. package/dist/providers/DeviceFlowProvider.d.ts.map +1 -1
  48. package/dist/providers/DeviceFlowProvider.js +17 -14
  49. package/dist/providers/OidcBrowserProvider.d.ts +5 -7
  50. package/dist/providers/OidcBrowserProvider.d.ts.map +1 -1
  51. package/dist/providers/OidcBrowserProvider.js +58 -61
  52. package/dist/providers/OidcDeviceFlowProvider.d.ts +2 -1
  53. package/dist/providers/OidcDeviceFlowProvider.d.ts.map +1 -1
  54. package/dist/providers/OidcDeviceFlowProvider.js +13 -11
  55. package/dist/providers/OidcPasswordProvider.d.ts +2 -1
  56. package/dist/providers/OidcPasswordProvider.d.ts.map +1 -1
  57. package/dist/providers/OidcPasswordProvider.js +4 -4
  58. package/dist/providers/OidcTokenExchangeProvider.d.ts +2 -1
  59. package/dist/providers/OidcTokenExchangeProvider.d.ts.map +1 -1
  60. package/dist/providers/OidcTokenExchangeProvider.js +3 -3
  61. package/dist/providers/Saml2BearerProvider.d.ts +4 -3
  62. package/dist/providers/Saml2BearerProvider.d.ts.map +1 -1
  63. package/dist/providers/Saml2BearerProvider.js +6 -3
  64. package/dist/providers/Saml2PureProvider.d.ts +4 -3
  65. package/dist/providers/Saml2PureProvider.d.ts.map +1 -1
  66. package/dist/providers/Saml2PureProvider.js +6 -3
  67. package/dist/providers/saml2Utils.d.ts +13 -12
  68. package/dist/providers/saml2Utils.d.ts.map +1 -1
  69. package/dist/providers/saml2Utils.js +46 -26
  70. package/dist/sso/SsoProviderFactory.d.ts +1 -1
  71. package/dist/sso/SsoProviderFactory.d.ts.map +1 -1
  72. package/dist/sso/types.d.ts +1 -1
  73. package/dist/sso/types.d.ts.map +1 -1
  74. package/dist/strategies/BrowserCallbackStrategy.d.ts +64 -0
  75. package/dist/strategies/BrowserCallbackStrategy.d.ts.map +1 -0
  76. package/dist/strategies/BrowserCallbackStrategy.js +210 -0
  77. package/dist/strategies/asOidcResult.d.ts +11 -0
  78. package/dist/strategies/asOidcResult.d.ts.map +1 -0
  79. package/dist/strategies/asOidcResult.js +30 -0
  80. package/dist/strategies/codeStrategies.d.ts +22 -0
  81. package/dist/strategies/codeStrategies.d.ts.map +1 -0
  82. package/dist/strategies/codeStrategies.js +39 -0
  83. package/dist/strategies/index.d.ts +8 -0
  84. package/dist/strategies/index.d.ts.map +1 -0
  85. package/dist/strategies/index.js +18 -0
  86. package/dist/strategies/manualStrategies.d.ts +20 -0
  87. package/dist/strategies/manualStrategies.d.ts.map +1 -0
  88. package/dist/strategies/manualStrategies.js +77 -0
  89. package/package.json +8 -5
  90. package/dist/auth/manualInput.d.ts +0 -5
  91. package/dist/auth/manualInput.d.ts.map +0 -1
  92. package/dist/auth/manualInput.js +0 -19
@@ -7,12 +7,11 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.AuthorizationCodeProvider = void 0;
10
- const interfaces_1 = require("@mcp-abap-adt/interfaces");
10
+ const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
11
11
  const browserAuth_1 = require("../auth/browserAuth");
12
12
  const tokenRefresher_1 = require("../auth/tokenRefresher");
13
+ const strategies_1 = require("../strategies");
13
14
  const BaseTokenProvider_1 = require("./BaseTokenProvider");
14
- /** How long an interactive login may wait for its callback. */
15
- const LOGIN_TIMEOUT_MS = 30 * 1000;
16
15
  /**
17
16
  * Authorization Code token provider
18
17
  *
@@ -32,8 +31,6 @@ class AuthorizationCodeProvider extends BaseTokenProvider_1.BaseTokenProvider {
32
31
  hasRefreshToken: !!config.refreshToken,
33
32
  accessToken: this.formatToken(config.accessToken),
34
33
  refreshToken: this.formatToken(config.refreshToken),
35
- browser: config.browser || 'none',
36
- redirectPort: config.redirectPort || 3001,
37
34
  });
38
35
  const missingFields = [];
39
36
  if (!config.uaaUrl) {
@@ -75,56 +72,70 @@ class AuthorizationCodeProvider extends BaseTokenProvider_1.BaseTokenProvider {
75
72
  return super.getTokens();
76
73
  }
77
74
  getAuthType() {
78
- return interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE;
75
+ return interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE;
79
76
  }
80
77
  async performLogin() {
81
- // Build authorization config
82
- // If authorizationUrl is provided, use it; otherwise startBrowserAuth will build it from uaaUrl + clientId
83
78
  const authConfig = {
84
79
  uaaUrl: this.config.uaaUrl,
85
80
  uaaClientId: this.config.clientId,
86
81
  uaaClientSecret: this.config.clientSecret,
87
82
  };
88
- // If pre-built URL provided, use it
89
- if (this.config.authorizationUrl) {
90
- authConfig.authorizationUrl = this.config.authorizationUrl;
83
+ const prebuilt = this.config.authorizationUrl;
84
+ const declaredRedirect = prebuilt
85
+ ? new URL(prebuilt).searchParams.get('redirect_uri')
86
+ : null;
87
+ const mismatch = (redirectUri) => `Pre-built authorizationUrl declares redirect_uri ${declaredRedirect}, ` +
88
+ `but the authorization strategy used ${redirectUri}, which does not match. ` +
89
+ 'An ephemeral port cannot be used with a pre-built URL.';
90
+ // The provider owns the URL; the strategy owns where it is answered. The
91
+ // guard lives here rather than after the fact because a mismatched redirect
92
+ // produces no callback at all — checking the outcome would mean waiting for
93
+ // a timeout that explains nothing.
94
+ const request = {
95
+ logger: this.logger,
96
+ buildAuthorizationUrl: async (redirectUri) => {
97
+ if (prebuilt) {
98
+ if (declaredRedirect && declaredRedirect !== redirectUri) {
99
+ throw new Error(mismatch(redirectUri));
100
+ }
101
+ return prebuilt;
102
+ }
103
+ return (0, browserAuth_1.getJwtAuthorizationUrl)(authConfig, redirectUri);
104
+ },
105
+ };
106
+ // Constructed here means disposed here: whoever constructs, disposes.
107
+ const supplied = this.config.authorization;
108
+ const strategy = supplied ?? (0, strategies_1.browserCallbackStrategy)();
109
+ let outcome;
110
+ try {
111
+ outcome = await strategy.authorize(request);
91
112
  }
92
- // Use provided browser or default to 'none' (prints URL to console)
93
- const browser = this.config.browser || 'none';
94
- const redirectPort = this.config.redirectPort || 3001;
95
- // Build authorization URL for logging (same logic as in startBrowserAuth)
96
- const authorizationUrl = authConfig.authorizationUrl ??
97
- `${authConfig.uaaUrl}/oauth/authorize?client_id=${encodeURIComponent(authConfig.uaaClientId)}&redirect_uri=${encodeURIComponent(`http://localhost:${redirectPort}/callback`)}&response_type=code`;
98
- this.logger?.info('[AuthorizationCodeProvider] Performing login via browser', {
99
- browser,
100
- redirectPort,
101
- authorizationUrl,
102
- uaaUrl: authConfig.uaaUrl,
103
- clientId: authConfig.uaaClientId,
104
- });
105
- // One timeout, owned by whoever owns the socket.
106
- //
107
- // This used to race startBrowserAuth against a second timer of the same
108
- // 30 seconds, so which fired was down to scheduling — and when the outer
109
- // one won, the provider rejected while the callback port was still bound.
110
- // That timer was never cleared either, keeping the event loop alive for the
111
- // rest of the window after a login that succeeded in a second.
112
- const result = await (0, browserAuth_1.startBrowserAuth)(authConfig, browser, this.logger || undefined, // Pass logger to browserAuth
113
- redirectPort, LOGIN_TIMEOUT_MS);
114
- this.logger?.info('[AuthorizationCodeProvider] Login completed', {
115
- hasAccessToken: !!result.accessToken,
116
- hasRefreshToken: !!result.refreshToken,
117
- accessToken: this.formatToken(result.accessToken),
118
- refreshToken: this.formatToken(result.refreshToken),
119
- accessTokenLength: result.accessToken?.length || 0,
113
+ finally {
114
+ if (!supplied) {
115
+ // A cleanup failure must not replace the reason the login failed.
116
+ await strategy.dispose?.().catch((error) => {
117
+ this.logger?.warn('[AuthorizationCodeProvider] dispose failed', {
118
+ error: error instanceof Error ? error.message : String(error),
119
+ });
120
+ });
121
+ }
122
+ }
123
+ // The second net. A strategy that never called the builder — `staticCodeStrategy`
124
+ // holds its payload already — passed the first check by not participating in
125
+ // it, and would otherwise reach the exchange with a redirect_uri the
126
+ // pre-built URL never advertised, earning an opaque `invalid_grant`.
127
+ if (declaredRedirect && declaredRedirect !== outcome.redirectUri) {
128
+ throw new Error(mismatch(outcome.redirectUri));
129
+ }
130
+ this.logger?.info('[AuthorizationCodeProvider] Code received', {
131
+ redirectUri: outcome.redirectUri,
120
132
  });
121
- // Parse expiration from JWT
122
- const expiresIn = this.calculateExpiresIn(result.accessToken);
133
+ const result = await (0, browserAuth_1.exchangeCodeForToken)(authConfig, outcome.payload, outcome.redirectUri, this.logger);
123
134
  return {
124
135
  authorizationToken: result.accessToken,
125
136
  refreshToken: result.refreshToken,
126
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE,
127
- expiresIn,
137
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE,
138
+ expiresIn: this.calculateExpiresIn(result.accessToken),
128
139
  };
129
140
  }
130
141
  async performRefresh() {
@@ -146,7 +157,7 @@ class AuthorizationCodeProvider extends BaseTokenProvider_1.BaseTokenProvider {
146
157
  return {
147
158
  authorizationToken: result.accessToken,
148
159
  refreshToken: result.refreshToken || this.refreshToken, // Keep old if new not provided
149
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE,
160
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE,
150
161
  expiresIn,
151
162
  };
152
163
  }
@@ -7,7 +7,8 @@
7
7
  * - Expiration checking
8
8
  * - Automatic refresh/relogin
9
9
  */
10
- import type { ILogger, ITokenProvider, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
10
+ import type { ITokenProvider, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
11
+ import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
11
12
  /**
12
13
  * Abstract base class for token providers
13
14
  *
@@ -1 +1 @@
1
- {"version":3,"file":"BaseTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/BaseTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;GAQG;AACH,8BAAsB,iBAAkB,YAAW,cAAc;IAC/D,SAAS,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACtC,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAWzD;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMzD;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,OAAO;IAyBjC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAExD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;IAE1D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,eAAe;IAEjD;;;;;;;;OAQG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAyElC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoC3E;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IA0BlD;;;;OAIG;IACH,SAAS,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA0BnE;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAShE"}
1
+ {"version":3,"file":"BaseTokenProvider.d.ts","sourceRoot":"","sources":["../../src/providers/BaseTokenProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAE9D;;;;;;;;GAQG;AACH,8BAAsB,iBAAkB,YAAW,cAAc;IAC/D,SAAS,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACtC,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,SAAS,CAAC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAWzD;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMzD;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,OAAO;IAyBjC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAExD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;IAE1D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,eAAe;IAEjD;;;;;;;;OAQG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAyElC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoC3E;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IA0BlD;;;;OAIG;IACH,SAAS,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA0BnE;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAShE"}
@@ -4,7 +4,7 @@
4
4
  * Uses client_credentials grant type for service-to-service authentication.
5
5
  * No browser required, no refresh token provided.
6
6
  */
7
- import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
7
+ import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
8
8
  import { BaseTokenProvider } from './BaseTokenProvider';
9
9
  export interface ClientCredentialsProviderConfig {
10
10
  uaaUrl: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ClientCredentialsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ClientCredentialsProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,SAAQ,iBAAiB;IAC9D,OAAO,CAAC,MAAM,CAAkC;gBAEpC,MAAM,EAAE,+BAA+B;IAuB7C,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAerC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAIxD"}
1
+ {"version":3,"file":"ClientCredentialsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ClientCredentialsProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,SAAQ,iBAAiB;IAC9D,OAAO,CAAC,MAAM,CAAkC;gBAEpC,MAAM,EAAE,+BAA+B;IAuB7C,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAerC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAIxD"}
@@ -7,7 +7,7 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.ClientCredentialsProvider = void 0;
10
- const interfaces_1 = require("@mcp-abap-adt/interfaces");
10
+ const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
11
11
  const clientCredentialsAuth_1 = require("../auth/clientCredentialsAuth");
12
12
  const BaseTokenProvider_1 = require("./BaseTokenProvider");
13
13
  /**
@@ -42,14 +42,14 @@ class ClientCredentialsProvider extends BaseTokenProvider_1.BaseTokenProvider {
42
42
  return super.getTokens();
43
43
  }
44
44
  getAuthType() {
45
- return interfaces_1.AUTH_TYPE_CLIENT_CREDENTIALS;
45
+ return interfaces_auth_1.AUTH_TYPE_CLIENT_CREDENTIALS;
46
46
  }
47
47
  async performLogin() {
48
48
  const result = await (0, clientCredentialsAuth_1.getTokenWithClientCredentials)(this.config.uaaUrl, this.config.clientId, this.config.clientSecret);
49
49
  return {
50
50
  authorizationToken: result.accessToken,
51
51
  refreshToken: undefined, // client_credentials doesn't provide refresh token
52
- authType: interfaces_1.AUTH_TYPE_CLIENT_CREDENTIALS,
52
+ authType: interfaces_auth_1.AUTH_TYPE_CLIENT_CREDENTIALS,
53
53
  expiresIn: result.expiresIn,
54
54
  };
55
55
  }
@@ -4,7 +4,8 @@
4
4
  * Uses OAuth2 Device Flow for devices without browser or input capabilities.
5
5
  * User authorizes on another device by entering a code.
6
6
  */
7
- import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
7
+ import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
8
+ import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
8
9
  import { BaseTokenProvider } from './BaseTokenProvider';
9
10
  export interface DeviceFlowProviderConfig {
10
11
  uaaUrl: string;
@@ -13,6 +14,7 @@ export interface DeviceFlowProviderConfig {
13
14
  scope?: string;
14
15
  accessToken?: string;
15
16
  refreshToken?: string;
17
+ logger?: ILogger;
16
18
  }
17
19
  /**
18
20
  * Device Flow token provider
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceFlowProvider.d.ts","sourceRoot":"","sources":["../../src/providers/DeviceFlowProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAO9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,EAAE,wBAAwB;IAa5C,SAAS,CAAC,WAAW,IAAI,eAAe;cAOxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cA0CrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CA2BxD"}
1
+ {"version":3,"file":"DeviceFlowProvider.d.ts","sourceRoot":"","sources":["../../src/providers/DeviceFlowProvider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAO9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD,OAAO,CAAC,MAAM,CAA2B;gBAE7B,MAAM,EAAE,wBAAwB;IAc5C,SAAS,CAAC,WAAW,IAAI,eAAe;cAOxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAyCrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CA2BxD"}
@@ -7,7 +7,8 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.DeviceFlowProvider = void 0;
10
- const interfaces_1 = require("@mcp-abap-adt/interfaces");
10
+ const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
11
+ const announce_1 = require("../auth/announce");
11
12
  const deviceFlowAuth_1 = require("../auth/deviceFlowAuth");
12
13
  const tokenRefresher_1 = require("../auth/tokenRefresher");
13
14
  const BaseTokenProvider_1 = require("./BaseTokenProvider");
@@ -22,6 +23,7 @@ class DeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
22
23
  constructor(config) {
23
24
  super();
24
25
  this.config = config;
26
+ this.logger = config.logger;
25
27
  if (config.accessToken) {
26
28
  this.authorizationToken = config.accessToken;
27
29
  this.expiresAt = this.parseExpirationFromJWT(config.accessToken);
@@ -34,28 +36,29 @@ class DeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
34
36
  // Device Flow is not a standard grant type in OAuth2 spec
35
37
  // We'll use a custom type or map it to authorization_code
36
38
  // For now, using authorization_code as it's similar
37
- return interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE;
39
+ return interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE;
38
40
  }
39
41
  async performLogin() {
40
42
  // Initiate device flow
41
- const deviceFlow = await (0, deviceFlowAuth_1.initiateDeviceFlow)(this.config.uaaUrl, this.config.clientId, this.config.scope, undefined);
42
- // Display user code and verification URI
43
- console.log('\n🔐 Device Flow Authorization');
44
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
45
- console.log(`📱 Go to: ${deviceFlow.verificationUri}`);
43
+ const deviceFlow = await (0, deviceFlowAuth_1.initiateDeviceFlow)(this.config.uaaUrl, this.config.clientId, this.config.scope, this.logger);
44
+ // Display user code and verification URI. This is a prompt the user must
45
+ // see to complete the flow, not a log line — it goes to the logger when
46
+ // there is one and to stderr otherwise, never to stdout.
47
+ const announce = (0, announce_1.announcer)(this.logger);
48
+ announce('Device Flow Authorization');
49
+ announce(`Go to: ${deviceFlow.verificationUri}`);
46
50
  if (deviceFlow.verificationUriComplete) {
47
- console.log(` Or use complete URL: ${deviceFlow.verificationUriComplete}`);
51
+ announce(`Or use complete URL: ${deviceFlow.verificationUriComplete}`);
48
52
  }
49
- console.log(`🔑 Enter code: ${deviceFlow.userCode}`);
50
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
51
- console.log('⏳ Waiting for authorization...\n');
53
+ announce(`Enter code: ${deviceFlow.userCode}`);
54
+ announce('Waiting for authorization...');
52
55
  // Poll for tokens
53
- const result = await (0, deviceFlowAuth_1.pollForDeviceTokens)(this.config.uaaUrl, this.config.clientId, this.config.clientSecret, deviceFlow.deviceCode, deviceFlow.interval, undefined);
56
+ const result = await (0, deviceFlowAuth_1.pollForDeviceTokens)(this.config.uaaUrl, this.config.clientId, this.config.clientSecret, deviceFlow.deviceCode, deviceFlow.interval, this.logger);
54
57
  const expiresIn = this.calculateExpiresIn(result.accessToken);
55
58
  return {
56
59
  authorizationToken: result.accessToken,
57
60
  refreshToken: result.refreshToken,
58
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE, // Device flow maps to authorization_code
61
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE, // Device flow maps to authorization_code
59
62
  expiresIn,
60
63
  };
61
64
  }
@@ -70,7 +73,7 @@ class DeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
70
73
  return {
71
74
  authorizationToken: result.accessToken,
72
75
  refreshToken: result.refreshToken || this.refreshToken,
73
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE,
76
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE,
74
77
  expiresIn,
75
78
  };
76
79
  }
@@ -1,20 +1,19 @@
1
1
  /**
2
2
  * OIDC Authorization Code Provider (with PKCE)
3
3
  */
4
- import type { ILogger, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
4
+ import type { IAuthorizationStrategy, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
5
+ import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
6
+ import type { OidcCallbackResult } from '../auth/oidcBrowserAuth';
5
7
  import { BaseTokenProvider } from './BaseTokenProvider';
6
8
  export interface OidcBrowserProviderConfig {
7
9
  issuerUrl?: string;
8
10
  clientId: string;
9
11
  clientSecret?: string;
10
12
  scopes?: string[];
11
- browser?: string;
12
- redirectPort?: number;
13
- redirectUri?: string;
14
- authorizationCode?: string;
15
- authorizationCodeProvider?: () => Promise<string>;
16
13
  authorizationEndpoint?: string;
17
14
  tokenEndpoint?: string;
15
+ /** How the login is conducted. Omitted means a browser callback on the default port. */
16
+ authorization?: IAuthorizationStrategy<OidcCallbackResult>;
18
17
  accessToken?: string;
19
18
  refreshToken?: string;
20
19
  logger?: ILogger;
@@ -25,6 +24,5 @@ export declare class OidcBrowserProvider extends BaseTokenProvider {
25
24
  protected getAuthType(): OAuth2GrantType;
26
25
  protected performLogin(): Promise<ITokenResult>;
27
26
  protected performRefresh(): Promise<ITokenResult>;
28
- private resolveAuthorizationCode;
29
27
  }
30
28
  //# sourceMappingURL=OidcBrowserProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OidcBrowserProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcBrowserProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,OAAO,CAAC,MAAM,CAA4B;gBAE9B,MAAM,EAAE,yBAAyB;IAc7C,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAsFrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;YAoCzC,wBAAwB;CA8BvC"}
1
+ {"version":3,"file":"OidcBrowserProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcBrowserProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAKlE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,aAAa,CAAC,EAAE,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,OAAO,CAAC,MAAM,CAA4B;gBAE9B,MAAM,EAAE,yBAAyB;IAc7C,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAyFrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAsCxD"}
@@ -4,11 +4,11 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OidcBrowserProvider = void 0;
7
- const interfaces_1 = require("@mcp-abap-adt/interfaces");
8
- const oidcBrowserAuth_1 = require("../auth/oidcBrowserAuth");
7
+ const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
9
8
  const oidcDiscovery_1 = require("../auth/oidcDiscovery");
10
9
  const oidcPkce_1 = require("../auth/oidcPkce");
11
10
  const oidcToken_1 = require("../auth/oidcToken");
11
+ const strategies_1 = require("../strategies");
12
12
  const BaseTokenProvider_1 = require("./BaseTokenProvider");
13
13
  class OidcBrowserProvider extends BaseTokenProvider_1.BaseTokenProvider {
14
14
  config;
@@ -25,57 +25,69 @@ class OidcBrowserProvider extends BaseTokenProvider_1.BaseTokenProvider {
25
25
  }
26
26
  }
27
27
  getAuthType() {
28
- return interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE;
28
+ return interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE;
29
29
  }
30
30
  async performLogin() {
31
- const needsAuthorizationEndpoint = !this.config.authorizationCode && !this.config.authorizationCodeProvider;
32
- const requiresDiscovery = (needsAuthorizationEndpoint && !this.config.authorizationEndpoint) ||
33
- !this.config.tokenEndpoint;
31
+ // One memoised discovery per login, started on first use rather than up
32
+ // front: a strategy that already holds a code must not drag in a request —
33
+ // nor the `issuerUrl` requirement that comes with it.
34
34
  let discovery = null;
35
- if (requiresDiscovery) {
36
- if (!this.config.issuerUrl) {
37
- throw new Error('OIDC issuerUrl is required when discovery is used');
35
+ const discover = () => {
36
+ if (!discovery) {
37
+ if (!this.config.issuerUrl) {
38
+ throw new Error('OIDC issuerUrl is required when discovery is used');
39
+ }
40
+ discovery = (0, oidcDiscovery_1.discoverOidc)(this.config.issuerUrl, this.logger);
38
41
  }
39
- discovery = await (0, oidcDiscovery_1.discoverOidc)(this.config.issuerUrl, this.logger);
42
+ return discovery;
43
+ };
44
+ const verifier = (0, oidcPkce_1.generatePkceVerifier)();
45
+ const challenge = (0, oidcPkce_1.generatePkceChallenge)(verifier);
46
+ const scope = (this.config.scopes && this.config.scopes.length > 0
47
+ ? this.config.scopes
48
+ : ['openid', 'profile', 'email']).join(' ');
49
+ const request = {
50
+ logger: this.logger,
51
+ buildAuthorizationUrl: async (redirectUri) => {
52
+ const endpoint = this.config.authorizationEndpoint ??
53
+ (await discover()).authorization_endpoint;
54
+ if (!endpoint) {
55
+ throw new Error('OIDC authorization endpoint is required (authorizationEndpoint or discovery)');
56
+ }
57
+ const params = new URLSearchParams();
58
+ params.append('response_type', 'code');
59
+ params.append('client_id', this.config.clientId);
60
+ params.append('redirect_uri', redirectUri);
61
+ params.append('scope', scope);
62
+ params.append('code_challenge', challenge);
63
+ params.append('code_challenge_method', 'S256');
64
+ return `${endpoint}?${params.toString()}`;
65
+ },
66
+ };
67
+ const supplied = this.config.authorization;
68
+ const strategy = supplied ?? (0, strategies_1.oidcCallbackStrategy)();
69
+ let outcome;
70
+ try {
71
+ outcome = await strategy.authorize(request);
40
72
  }
41
- const authorizationEndpoint = needsAuthorizationEndpoint
42
- ? this.config.authorizationEndpoint || discovery?.authorization_endpoint
43
- : undefined;
44
- const tokenEndpoint = this.config.tokenEndpoint || discovery?.token_endpoint;
45
- if (needsAuthorizationEndpoint && !authorizationEndpoint) {
46
- throw new Error('OIDC authorization endpoint is required (authorizationEndpoint or discovery)');
73
+ finally {
74
+ if (!supplied) {
75
+ await strategy.dispose?.().catch((error) => {
76
+ this.logger?.warn('[OidcBrowserProvider] dispose failed', {
77
+ error: error instanceof Error ? error.message : String(error),
78
+ });
79
+ });
80
+ }
47
81
  }
82
+ const tokenEndpoint = this.config.tokenEndpoint ?? (await discover()).token_endpoint;
48
83
  if (!tokenEndpoint) {
49
84
  throw new Error('OIDC token endpoint is required (tokenEndpoint or discovery)');
50
85
  }
51
- const redirectPort = this.config.redirectPort || 3001;
52
- const redirectUri = this.config.redirectUri || `http://localhost:${redirectPort}/callback`;
53
- if (needsAuthorizationEndpoint && this.config.redirectUri) {
54
- if (!redirectUri.startsWith('http://localhost:')) {
55
- throw new Error('OIDC redirectUri must be localhost for browser callback flow');
56
- }
57
- }
58
- const scope = (this.config.scopes && this.config.scopes.length > 0
59
- ? this.config.scopes
60
- : ['openid', 'profile', 'email']).join(' ');
61
- const verifier = (0, oidcPkce_1.generatePkceVerifier)();
62
- const challenge = (0, oidcPkce_1.generatePkceChallenge)(verifier);
63
- const params = new URLSearchParams();
64
- params.append('response_type', 'code');
65
- params.append('client_id', this.config.clientId);
66
- params.append('redirect_uri', redirectUri);
67
- params.append('scope', scope);
68
- params.append('code_challenge', challenge);
69
- params.append('code_challenge_method', 'S256');
70
- const authorizationUrl = needsAuthorizationEndpoint
71
- ? `${authorizationEndpoint}?${params.toString()}`
72
- : undefined;
73
- const code = await this.resolveAuthorizationCode(authorizationUrl, redirectPort);
74
- const tokens = await (0, oidcToken_1.exchangeAuthorizationCode)(tokenEndpoint, this.config.clientId, this.config.clientSecret, code, redirectUri, verifier, this.logger);
86
+ const tokens = await (0, oidcToken_1.exchangeAuthorizationCode)(tokenEndpoint, this.config.clientId, this.config.clientSecret, outcome.payload.code, outcome.redirectUri, verifier, this.logger);
75
87
  return {
76
88
  authorizationToken: tokens.accessToken,
77
89
  refreshToken: tokens.refreshToken,
78
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE,
90
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE,
79
91
  expiresIn: tokens.expiresIn,
80
92
  tokenType: 'jwt',
81
93
  };
@@ -91,7 +103,10 @@ class OidcBrowserProvider extends BaseTokenProvider_1.BaseTokenProvider {
91
103
  }
92
104
  discovery = await (0, oidcDiscovery_1.discoverOidc)(this.config.issuerUrl, this.logger);
93
105
  }
94
- const tokenEndpoint = this.config.tokenEndpoint || discovery?.token_endpoint;
106
+ // `??`, matching the `=== undefined` gate above and the login path: `||`
107
+ // treated a configured-but-empty endpoint as absent while the gate had
108
+ // already decided it was present, so the two disagreed about the same value.
109
+ const tokenEndpoint = this.config.tokenEndpoint ?? discovery?.token_endpoint;
95
110
  if (!tokenEndpoint) {
96
111
  throw new Error('OIDC token endpoint is required (tokenEndpoint or discovery)');
97
112
  }
@@ -99,28 +114,10 @@ class OidcBrowserProvider extends BaseTokenProvider_1.BaseTokenProvider {
99
114
  return {
100
115
  authorizationToken: tokens.accessToken,
101
116
  refreshToken: tokens.refreshToken || this.refreshToken,
102
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE,
117
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE,
103
118
  expiresIn: tokens.expiresIn,
104
119
  tokenType: 'jwt',
105
120
  };
106
121
  }
107
- async resolveAuthorizationCode(authorizationUrl, redirectPort) {
108
- if (this.config.authorizationCode) {
109
- return this.config.authorizationCode;
110
- }
111
- if (this.config.authorizationCodeProvider) {
112
- const code = await this.config.authorizationCodeProvider();
113
- if (!code) {
114
- throw new Error('Authorization code provider returned empty value');
115
- }
116
- return code;
117
- }
118
- if (!authorizationUrl) {
119
- throw new Error('OIDC authorization URL is required when using browser flow');
120
- }
121
- const browser = this.config.browser || 'auto';
122
- const { code } = await (0, oidcBrowserAuth_1.startOidcBrowserAuth)(authorizationUrl, browser, this.logger, redirectPort);
123
- return code;
124
- }
125
122
  }
126
123
  exports.OidcBrowserProvider = OidcBrowserProvider;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * OIDC Device Flow Provider
3
3
  */
4
- import type { ILogger, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
4
+ import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
5
+ import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
5
6
  import { BaseTokenProvider } from './BaseTokenProvider';
6
7
  export interface OidcDeviceFlowProviderConfig {
7
8
  issuerUrl?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"OidcDeviceFlowProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcDeviceFlowProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAQlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,sBAAuB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,EAAE,4BAA4B;IAchD,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAuErC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAqCxD"}
1
+ {"version":3,"file":"OidcDeviceFlowProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcDeviceFlowProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAQ9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,sBAAuB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,MAAM,CAA+B;gBAEjC,MAAM,EAAE,4BAA4B;IAchD,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAwErC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAqCxD"}
@@ -4,7 +4,8 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OidcDeviceFlowProvider = void 0;
7
- const interfaces_1 = require("@mcp-abap-adt/interfaces");
7
+ const interfaces_auth_1 = require("@mcp-abap-adt/interfaces-auth");
8
+ const announce_1 = require("../auth/announce");
8
9
  const oidcDiscovery_1 = require("../auth/oidcDiscovery");
9
10
  const oidcToken_1 = require("../auth/oidcToken");
10
11
  const BaseTokenProvider_1 = require("./BaseTokenProvider");
@@ -23,7 +24,7 @@ class OidcDeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
23
24
  }
24
25
  }
25
26
  getAuthType() {
26
- return interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE;
27
+ return interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE;
27
28
  }
28
29
  async performLogin() {
29
30
  if (!this.config.deviceAuthorizationEndpoint &&
@@ -50,20 +51,21 @@ class OidcDeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
50
51
  }
51
52
  const scope = this.config.scopes?.join(' ');
52
53
  const deviceFlow = await (0, oidcToken_1.initiateDeviceAuthorization)(deviceAuthorizationEndpoint, this.config.clientId, scope, this.logger);
53
- // Manual user guidance
54
- console.log('');
55
- console.log('OIDC device authorization');
56
- console.log('Go to:', deviceFlow.verificationUri);
54
+ // Manual user guidance. This is a prompt the user must see to complete
55
+ // the flow, not a log line — it goes to the logger when there is one and
56
+ // to stderr otherwise, never to stdout.
57
+ const announce = (0, announce_1.announcer)(this.logger);
58
+ announce('OIDC device authorization');
59
+ announce(`Go to: ${deviceFlow.verificationUri}`);
57
60
  if (deviceFlow.verificationUriComplete) {
58
- console.log('Or use:', deviceFlow.verificationUriComplete);
61
+ announce(`Or use: ${deviceFlow.verificationUriComplete}`);
59
62
  }
60
- console.log('Enter code:', deviceFlow.userCode);
61
- console.log('');
63
+ announce(`Enter code: ${deviceFlow.userCode}`);
62
64
  const tokens = await (0, oidcToken_1.pollDeviceTokens)(tokenEndpoint, this.config.clientId, this.config.clientSecret, deviceFlow.deviceCode, deviceFlow.interval || 5, this.logger);
63
65
  return {
64
66
  authorizationToken: tokens.accessToken,
65
67
  refreshToken: tokens.refreshToken,
66
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE,
68
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE,
67
69
  expiresIn: tokens.expiresIn,
68
70
  tokenType: 'jwt',
69
71
  };
@@ -90,7 +92,7 @@ class OidcDeviceFlowProvider extends BaseTokenProvider_1.BaseTokenProvider {
90
92
  return {
91
93
  authorizationToken: tokens.accessToken,
92
94
  refreshToken: tokens.refreshToken || this.refreshToken,
93
- authType: interfaces_1.AUTH_TYPE_AUTHORIZATION_CODE,
95
+ authType: interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE,
94
96
  expiresIn: tokens.expiresIn,
95
97
  tokenType: 'jwt',
96
98
  };
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * OIDC Password Grant Provider
3
3
  */
4
- import type { ILogger, ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces';
4
+ import type { ITokenResult, OAuth2GrantType } from '@mcp-abap-adt/interfaces-auth';
5
+ import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
5
6
  import { BaseTokenProvider } from './BaseTokenProvider';
6
7
  export interface OidcPasswordProviderConfig {
7
8
  issuerUrl?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"OidcPasswordProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcPasswordProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EACZ,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,oBAAqB,SAAQ,iBAAiB;IACzD,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,EAAE,0BAA0B;IAc9C,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAsCrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAsCxD"}
1
+ {"version":3,"file":"OidcPasswordProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcPasswordProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAG9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,oBAAqB,SAAQ,iBAAiB;IACzD,OAAO,CAAC,MAAM,CAA6B;gBAE/B,MAAM,EAAE,0BAA0B;IAc9C,SAAS,CAAC,WAAW,IAAI,eAAe;cAIxB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;cAsCrC,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAsCxD"}