@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.
- package/CHANGELOG.md +135 -0
- package/COPYING +674 -0
- package/LICENSE +160 -17
- package/README.md +401 -66
- package/bin/auth-authorization-code.ts +5 -3
- package/dist/__tests__/helpers/netHelpers.d.ts +16 -0
- package/dist/__tests__/helpers/netHelpers.d.ts.map +1 -1
- package/dist/__tests__/helpers/netHelpers.js +29 -0
- package/dist/__tests__/helpers/testLogger.d.ts +1 -1
- package/dist/__tests__/helpers/testLogger.d.ts.map +1 -1
- package/dist/auth/announce.d.ts +11 -0
- package/dist/auth/announce.d.ts.map +1 -0
- package/dist/auth/announce.js +19 -0
- package/dist/auth/browserAuth.d.ts +23 -15
- package/dist/auth/browserAuth.d.ts.map +1 -1
- package/dist/auth/browserAuth.js +25 -111
- package/dist/auth/callbackServer.d.ts +7 -1
- package/dist/auth/callbackServer.d.ts.map +1 -1
- package/dist/auth/callbackServer.js +31 -21
- package/dist/auth/deviceFlowAuth.d.ts +1 -1
- package/dist/auth/deviceFlowAuth.d.ts.map +1 -1
- package/dist/auth/oidcBrowserAuth.d.ts +2 -9
- package/dist/auth/oidcBrowserAuth.d.ts.map +1 -1
- package/dist/auth/oidcBrowserAuth.js +16 -125
- package/dist/auth/oidcDiscovery.d.ts +1 -1
- package/dist/auth/oidcDiscovery.d.ts.map +1 -1
- package/dist/auth/oidcToken.d.ts +1 -1
- package/dist/auth/oidcToken.d.ts.map +1 -1
- package/dist/auth/saml2Auth.d.ts +2 -9
- package/dist/auth/saml2Auth.d.ts.map +1 -1
- package/dist/auth/saml2Auth.js +10 -130
- package/dist/auth/saml2TokenExchange.d.ts +1 -1
- package/dist/auth/saml2TokenExchange.d.ts.map +1 -1
- package/dist/errors/TokenProviderErrors.js +6 -6
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -1
- package/dist/providers/AuthorizationCodeProvider.d.ts +8 -3
- package/dist/providers/AuthorizationCodeProvider.d.ts.map +1 -1
- package/dist/providers/AuthorizationCodeProvider.js +55 -44
- package/dist/providers/BaseTokenProvider.d.ts +2 -1
- package/dist/providers/BaseTokenProvider.d.ts.map +1 -1
- package/dist/providers/ClientCredentialsProvider.d.ts +1 -1
- package/dist/providers/ClientCredentialsProvider.d.ts.map +1 -1
- package/dist/providers/ClientCredentialsProvider.js +3 -3
- package/dist/providers/DeviceFlowProvider.d.ts +3 -1
- package/dist/providers/DeviceFlowProvider.d.ts.map +1 -1
- package/dist/providers/DeviceFlowProvider.js +17 -14
- package/dist/providers/OidcBrowserProvider.d.ts +5 -7
- package/dist/providers/OidcBrowserProvider.d.ts.map +1 -1
- package/dist/providers/OidcBrowserProvider.js +58 -61
- package/dist/providers/OidcDeviceFlowProvider.d.ts +2 -1
- package/dist/providers/OidcDeviceFlowProvider.d.ts.map +1 -1
- package/dist/providers/OidcDeviceFlowProvider.js +13 -11
- package/dist/providers/OidcPasswordProvider.d.ts +2 -1
- package/dist/providers/OidcPasswordProvider.d.ts.map +1 -1
- package/dist/providers/OidcPasswordProvider.js +4 -4
- package/dist/providers/OidcTokenExchangeProvider.d.ts +2 -1
- package/dist/providers/OidcTokenExchangeProvider.d.ts.map +1 -1
- package/dist/providers/OidcTokenExchangeProvider.js +3 -3
- package/dist/providers/Saml2BearerProvider.d.ts +4 -3
- package/dist/providers/Saml2BearerProvider.d.ts.map +1 -1
- package/dist/providers/Saml2BearerProvider.js +6 -3
- package/dist/providers/Saml2PureProvider.d.ts +4 -3
- package/dist/providers/Saml2PureProvider.d.ts.map +1 -1
- package/dist/providers/Saml2PureProvider.js +6 -3
- package/dist/providers/saml2Utils.d.ts +13 -12
- package/dist/providers/saml2Utils.d.ts.map +1 -1
- package/dist/providers/saml2Utils.js +46 -26
- package/dist/sso/SsoProviderFactory.d.ts +1 -1
- package/dist/sso/SsoProviderFactory.d.ts.map +1 -1
- package/dist/sso/types.d.ts +1 -1
- package/dist/sso/types.d.ts.map +1 -1
- package/dist/strategies/BrowserCallbackStrategy.d.ts +64 -0
- package/dist/strategies/BrowserCallbackStrategy.d.ts.map +1 -0
- package/dist/strategies/BrowserCallbackStrategy.js +210 -0
- package/dist/strategies/asOidcResult.d.ts +11 -0
- package/dist/strategies/asOidcResult.d.ts.map +1 -0
- package/dist/strategies/asOidcResult.js +30 -0
- package/dist/strategies/codeStrategies.d.ts +22 -0
- package/dist/strategies/codeStrategies.d.ts.map +1 -0
- package/dist/strategies/codeStrategies.js +39 -0
- package/dist/strategies/index.d.ts +8 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +18 -0
- package/dist/strategies/manualStrategies.d.ts +20 -0
- package/dist/strategies/manualStrategies.d.ts.map +1 -0
- package/dist/strategies/manualStrategies.js +77 -0
- package/package.json +8 -5
- package/dist/auth/manualInput.d.ts +0 -5
- package/dist/auth/manualInput.d.ts.map +0 -1
- 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
|
|
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
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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 {
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
42
|
-
// Display user code and verification URI
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
51
|
+
announce(`Or use complete URL: ${deviceFlow.verificationUriComplete}`);
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
|
|
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,
|
|
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:
|
|
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:
|
|
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 {
|
|
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,
|
|
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
|
|
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
|
|
28
|
+
return interfaces_auth_1.AUTH_TYPE_AUTHORIZATION_CODE_PKCE;
|
|
29
29
|
}
|
|
30
30
|
async performLogin() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
if (!
|
|
37
|
-
|
|
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
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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 {
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
61
|
+
announce(`Or use: ${deviceFlow.verificationUriComplete}`);
|
|
59
62
|
}
|
|
60
|
-
|
|
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:
|
|
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:
|
|
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 {
|
|
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,
|
|
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"}
|