@api-client/core 0.5.20 → 0.5.23

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 (62) hide show
  1. package/build/browser.d.ts +7 -0
  2. package/build/browser.js +10 -0
  3. package/build/browser.js.map +1 -1
  4. package/build/index.d.ts +4 -0
  5. package/build/index.js +7 -0
  6. package/build/index.js.map +1 -1
  7. package/build/src/authorization/AuthorizationError.d.ts +23 -0
  8. package/build/src/authorization/AuthorizationError.js +33 -0
  9. package/build/src/authorization/AuthorizationError.js.map +1 -0
  10. package/build/src/authorization/CustomParameters.d.ts +24 -0
  11. package/build/src/authorization/CustomParameters.js +59 -0
  12. package/build/src/authorization/CustomParameters.js.map +1 -0
  13. package/build/src/authorization/OAuth2Authorization.d.ts +332 -0
  14. package/build/src/authorization/OAuth2Authorization.js +965 -0
  15. package/build/src/authorization/OAuth2Authorization.js.map +1 -0
  16. package/build/src/authorization/OidcAuthorization.d.ts +34 -0
  17. package/build/src/authorization/OidcAuthorization.js +139 -0
  18. package/build/src/authorization/OidcAuthorization.js.map +1 -0
  19. package/build/src/authorization/Utils.d.ts +51 -0
  20. package/build/src/authorization/Utils.js +122 -0
  21. package/build/src/authorization/Utils.js.map +1 -0
  22. package/build/src/authorization/lib/IframeAuthorization.d.ts +53 -0
  23. package/build/src/authorization/lib/IframeAuthorization.js +116 -0
  24. package/build/src/authorization/lib/IframeAuthorization.js.map +1 -0
  25. package/build/src/authorization/lib/KnownGrants.d.ts +6 -0
  26. package/build/src/authorization/lib/KnownGrants.js +7 -0
  27. package/build/src/authorization/lib/KnownGrants.js.map +1 -0
  28. package/build/src/authorization/lib/PopupAuthorization.d.ts +41 -0
  29. package/build/src/authorization/lib/PopupAuthorization.js +73 -0
  30. package/build/src/authorization/lib/PopupAuthorization.js.map +1 -0
  31. package/build/src/authorization/lib/Tokens.d.ts +55 -0
  32. package/build/src/authorization/lib/Tokens.js +117 -0
  33. package/build/src/authorization/lib/Tokens.js.map +1 -0
  34. package/build/src/authorization/types.d.ts +174 -0
  35. package/build/src/authorization/types.js +2 -0
  36. package/build/src/authorization/types.js.map +1 -0
  37. package/build/src/models/Authorization.d.ts +3 -5
  38. package/build/src/models/RequestAuthorization.js +4 -0
  39. package/build/src/models/RequestAuthorization.js.map +1 -1
  40. package/build/src/runtime/actions/runnable/DeleteCookieRunnable.d.ts +1 -1
  41. package/build/src/runtime/actions/runnable/SetCookieRunnable.d.ts +1 -1
  42. package/build/src/runtime/actions/runnable/SetVariableRunnable.d.ts +1 -1
  43. package/build/src/runtime/modules/RequestAuthorization.js +3 -7
  44. package/build/src/runtime/modules/RequestAuthorization.js.map +1 -1
  45. package/oauth-popup.html +29 -0
  46. package/package.json +3 -1
  47. package/src/authorization/AuthorizationError.ts +25 -0
  48. package/src/authorization/CustomParameters.ts +61 -0
  49. package/src/authorization/OAuth2Authorization.ts +1027 -0
  50. package/src/authorization/OidcAuthorization.ts +143 -0
  51. package/src/authorization/Utils.ts +126 -0
  52. package/src/authorization/lib/IframeAuthorization.ts +128 -0
  53. package/src/authorization/lib/KnownGrants.ts +6 -0
  54. package/src/authorization/lib/PopupAuthorization.ts +80 -0
  55. package/src/authorization/lib/Tokens.ts +124 -0
  56. package/src/authorization/types.ts +176 -0
  57. package/src/models/Authorization.ts +4 -5
  58. package/src/models/RequestAuthorization.ts +5 -1
  59. package/src/runtime/actions/runnable/DeleteCookieRunnable.ts +1 -1
  60. package/src/runtime/actions/runnable/SetCookieRunnable.ts +2 -2
  61. package/src/runtime/actions/runnable/SetVariableRunnable.ts +1 -1
  62. package/src/runtime/modules/RequestAuthorization.ts +3 -7
@@ -0,0 +1,143 @@
1
+ import { IOidcTokenInfo, IOidcTokenError, ITokenInfo } from '../models/Authorization.js';
2
+ import { Tokens } from './lib/Tokens.js';
3
+ import { OAuth2Authorization, grantResponseMapping, reportOAuthError, resolveFunction, rejectFunction, handleTokenInfo } from './OAuth2Authorization.js';
4
+ import { nonceGenerator } from './Utils.js';
5
+
6
+ export class OidcAuthorization extends OAuth2Authorization {
7
+ /**
8
+ * @returns The parameters to build popup URL.
9
+ */
10
+ async buildPopupUrlParams(): Promise<URL | null> {
11
+ const url = await super.buildPopupUrlParams();
12
+ if (url === null) {
13
+ return url;
14
+ }
15
+ const type = (this.settings.responseType || grantResponseMapping[this.settings.grantType!]);
16
+ // ID token nonce
17
+ if (type.includes('id_token')) {
18
+ url.searchParams.set('nonce', nonceGenerator());
19
+ }
20
+ return url;
21
+ }
22
+
23
+ /**
24
+ * @param params The instance of search params with the response from the auth dialog.
25
+ * @returns true when the params qualify as an authorization popup redirect response.
26
+ */
27
+ validateTokenResponse(params: URLSearchParams): boolean {
28
+ if (params.has('id_token')) {
29
+ return true;
30
+ }
31
+ return super.validateTokenResponse(params);
32
+ }
33
+
34
+ /**
35
+ * Processes the response returned by the popup or the iframe.
36
+ */
37
+ async processTokenResponse(params: URLSearchParams): Promise<void> {
38
+ this.clearObservers();
39
+ const state = params.get('state');
40
+ if (!state) {
41
+ this[reportOAuthError]('Server did not return the state parameter.', 'no_state');
42
+ return;
43
+ }
44
+ if (state !== this.state) {
45
+ // The authorization class (this) is created per token request so this can only have one state.
46
+ // When the app requests for more tokens at the same time is should create multiple instances of this.
47
+ this[reportOAuthError]('The state value returned by the authorization server is invalid.', 'invalid_state');
48
+ return;
49
+ }
50
+ if (params.has('error')) {
51
+ const info = this.createTokenResponseError(params);
52
+ // @ts-ignore
53
+ this[reportOAuthError](...info);
54
+ return;
55
+ }
56
+ // this is the time when the tokens are received. +- a few ms.
57
+ const time = Date.now();
58
+ const tokens: (IOidcTokenInfo|IOidcTokenError)[] | null = this.prepareTokens(params, time);
59
+ if (!Array.isArray(tokens) || !tokens.length) {
60
+ this[reportOAuthError]('The authorization response has unknown response type configuration.', 'unknown_state');
61
+ return;
62
+ }
63
+ const codeIndex = tokens.findIndex(i => i.responseType === 'code');
64
+ if (codeIndex >= 0) {
65
+ const codeToken = tokens[codeIndex] as IOidcTokenInfo;
66
+ try {
67
+ const info = await this.getCodeInfo(codeToken.code!);
68
+ if (info.error) {
69
+ tokens[codeIndex] = {
70
+ responseType: codeToken.responseType,
71
+ state: codeToken.state,
72
+ error: info.error,
73
+ errorDescription: info.errorDescription,
74
+ } as IOidcTokenError;
75
+ } else {
76
+ codeToken.accessToken = info.accessToken;
77
+ codeToken.refreshToken = info.refreshToken;
78
+ codeToken.idToken = info.idToken;
79
+ codeToken.tokenType = info.tokenType;
80
+ codeToken.expiresIn = info.expiresIn;
81
+ codeToken.scope = Tokens.computeTokenInfoScopes(this.settings.scopes, info.scope);
82
+ }
83
+ } catch (e) {
84
+ tokens[codeIndex] = {
85
+ responseType: codeToken.responseType,
86
+ state: codeToken.state,
87
+ error: 'unknown_state',
88
+ errorDescription: (e as Error).message,
89
+ } as IOidcTokenError;
90
+ }
91
+ }
92
+ this.finish(tokens);
93
+ }
94
+
95
+ /**
96
+ * Creates a token info object for each requested response type. These are created from the params received from the
97
+ * redirect URI. This means that it might not be complete (for code response type).
98
+ * @param params
99
+ * @param time Timestamp when the tokens were created
100
+ */
101
+ prepareTokens(params: URLSearchParams, time: number): IOidcTokenInfo[] | null {
102
+ const { grantType, responseType='', scopes } = this.settings;
103
+ let type = responseType;
104
+ if (!type) {
105
+ type = grantResponseMapping[grantType!];
106
+ }
107
+ if (!type) {
108
+ return null;
109
+ }
110
+ const types = type.split(' ').map(i => i.trim()).filter(i => !!i);
111
+ const result: IOidcTokenInfo[] = [];
112
+ types.forEach(item => {
113
+ const info = Tokens.createTokenInfo(item, params, time, scopes);
114
+ if (info) {
115
+ result.push(info);
116
+ }
117
+ });
118
+ return result;
119
+ }
120
+
121
+ /**
122
+ * Finishes the authorization.
123
+ */
124
+ finish(tokens: (IOidcTokenInfo|IOidcTokenError)[]): void {
125
+ if (this[resolveFunction]) {
126
+ this[resolveFunction]!(tokens as any);
127
+ }
128
+ this[rejectFunction] = undefined;
129
+ this[resolveFunction] = undefined;
130
+ }
131
+
132
+ /**
133
+ * Processes token info object when it's ready.
134
+ *
135
+ * @param info Token info returned from the server.
136
+ */
137
+ [handleTokenInfo](info: ITokenInfo): void {
138
+ const { responseType } = this.settings;
139
+ const token = Tokens.fromTokenInfo(info);
140
+ token.responseType = responseType || '';
141
+ this.finish([token]);
142
+ }
143
+ }
@@ -0,0 +1,126 @@
1
+ import { IOAuth2Authorization } from "../models/Authorization.js";
2
+
3
+ /**
4
+ * Checks if the URL has valid scheme for OAuth flow.
5
+ *
6
+ * Do not use this to validate redirect URIs as they can use any protocol.
7
+ *
8
+ * @param url The url value to test
9
+ * @throws {TypeError} When passed value is not set, empty, or not a string
10
+ * @throws {Error} When passed value is not a valid URL for OAuth 2 flow
11
+ */
12
+ export function checkUrl(url: string): void {
13
+ if (!url) {
14
+ throw new TypeError("the value is missing");
15
+ }
16
+ if (typeof url !== "string") {
17
+ throw new TypeError("the value is not a string");
18
+ }
19
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
20
+ throw new Error("the value has invalid scheme");
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Checks if basic configuration of the OAuth 2 request is valid an can proceed
26
+ * with authentication.
27
+ * @param settings authorization settings
28
+ * @throws {Error} When settings are not valid
29
+ */
30
+ export function sanityCheck(settings: IOAuth2Authorization): void {
31
+ if (["implicit", "authorization_code"].includes(settings.grantType!)) {
32
+ try {
33
+ checkUrl(settings.authorizationUri!);
34
+ } catch (e) {
35
+ throw new Error(`authorizationUri: ${(e as Error).message}`);
36
+ }
37
+ if (settings.accessTokenUri) {
38
+ try {
39
+ checkUrl(settings.accessTokenUri);
40
+ } catch (e) {
41
+ throw new Error(`accessTokenUri: ${(e as Error).message}`);
42
+ }
43
+ }
44
+ } else if (settings.accessTokenUri) {
45
+ try {
46
+ checkUrl(settings.accessTokenUri);
47
+ } catch (e) {
48
+ throw new Error(`accessTokenUri: ${(e as Error).message}`);
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Generates a random string of characters.
55
+ *
56
+ * @returns A random string.
57
+ */
58
+ export function randomString(): string {
59
+ const array = new Uint32Array(28);
60
+ window.crypto.getRandomValues(array);
61
+ return Array.from(array, (dec) => `0${dec.toString(16)}`.substr(-2)).join("");
62
+ }
63
+
64
+ /**
65
+ * Replaces `-` or `_` with camel case.
66
+ * @param {string} name The string to process
67
+ * @return {String|undefined} Camel cased string or `undefined` if not transformed.
68
+ */
69
+ export function camel(name: string): string | undefined {
70
+ let i = 0;
71
+ let l;
72
+ let changed = false;
73
+ // eslint-disable-next-line no-cond-assign
74
+ while ((l = name[i])) {
75
+ if ((l === "_" || l === "-") && i + 1 < name.length) {
76
+ // eslint-disable-next-line no-param-reassign
77
+ name = name.substr(0, i) + name[i + 1].toUpperCase() + name.substr(i + 2);
78
+ changed = true;
79
+ }
80
+ // eslint-disable-next-line no-plusplus
81
+ i++;
82
+ }
83
+ return changed ? name : undefined;
84
+ }
85
+
86
+ /**
87
+ * Computes the SHA256 hash ogf the given input.
88
+ * @param value The value to encode.
89
+ */
90
+ export async function sha256(value: string): Promise<ArrayBuffer> {
91
+ const encoder = new TextEncoder();
92
+ const data = encoder.encode(value);
93
+ return window.crypto.subtle.digest("SHA-256", data);
94
+ }
95
+
96
+ /**
97
+ * Encoded the array buffer to a base64 string value.
98
+ */
99
+ export function base64Buffer(buffer: ArrayBuffer): string {
100
+ const view = new Uint8Array(buffer);
101
+ const str = String.fromCharCode.apply(null, view as any);
102
+ return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
103
+ }
104
+
105
+ /**
106
+ * Generates code challenge for the PKCE extension to the OAuth2 specification.
107
+ * @param verifier The generated code verifier.
108
+ * @returns The code challenge string
109
+ */
110
+ export async function generateCodeChallenge(verifier: string): Promise<string> {
111
+ const hashed = await sha256(verifier);
112
+ return base64Buffer(hashed);
113
+ }
114
+
115
+ /**
116
+ * Generates cryptographically significant random string.
117
+ * @param size The size of the generated nonce.
118
+ * @returns A nonce (number used once).
119
+ */
120
+ export function nonceGenerator(size = 20): string {
121
+ const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
122
+ let array = new Uint8Array(size);
123
+ window.crypto.getRandomValues(array);
124
+ array = array.map(x => validChars.charCodeAt(x % validChars.length));
125
+ return String.fromCharCode.apply(null, array as any);
126
+ }
@@ -0,0 +1,128 @@
1
+ /* eslint-disable class-methods-use-this */
2
+ export const loadHandler = Symbol('loadHandler');
3
+ export const timeoutValue = Symbol('timeoutValue');
4
+ export const checkInterval = Symbol('checkInterval');
5
+ export const limitValue = Symbol('limitValue');
6
+ export const targetValue = Symbol('targetValue');
7
+
8
+ /**
9
+ * Adds the support for the iframe authorization.
10
+ *
11
+ * This class creates and loads an iframe for the given URL. Then it runs a timer recursively
12
+ * that increases its interval multiplying its last timeout value by 2.
13
+ * The the timer reaches timeout it dispatches the timeout event.
14
+ *
15
+ * The library takes into the account the redirects.
16
+ *
17
+ * Call the `cancel()` and the `cleanUp()` functions when the authorization data is received.
18
+ */
19
+ export class IframeAuthorization extends EventTarget {
20
+ loadTimeout?: any;
21
+
22
+ timedOut = false;
23
+
24
+ [timeoutValue] = 8;
25
+
26
+ [limitValue]: number;
27
+
28
+ [targetValue]: HTMLElement;
29
+
30
+ frame?: HTMLIFrameElement;
31
+
32
+ /**
33
+ * @param limit The timeout limit after which the library calls timeout if it wasn't cancelled.
34
+ * @param target A target node where to add the iframe into.
35
+ */
36
+ constructor(limit=1020, target:HTMLElement=document.body) {
37
+ super();
38
+ this[limitValue] = limit;
39
+ this[targetValue] = target;
40
+
41
+ this[loadHandler] = this[loadHandler].bind(this);
42
+ this[checkInterval] = this[checkInterval].bind(this);
43
+ }
44
+
45
+ /**
46
+ * A function to be called when the timer is no longer needed.
47
+ */
48
+ cancel(): void {
49
+ if (this.loadTimeout) {
50
+ clearTimeout(this.loadTimeout);
51
+ this.loadTimeout = undefined;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Removes any existing frame and removes any remaining listeners.
57
+ */
58
+ cleanUp(): void {
59
+ if (!this.frame) {
60
+ return;
61
+ }
62
+ this.frame.removeEventListener('load', this[loadHandler]);
63
+ if (this.frame.parentElement) {
64
+ this.frame.parentElement.removeChild(this.frame);
65
+ }
66
+ this.frame = undefined;
67
+ }
68
+
69
+ /**
70
+ * Creates an invisible frame and loads the given URL
71
+ * @param url THe resource to load.
72
+ */
73
+ load(url: string): void {
74
+ const iframe = document.createElement('iframe');
75
+ iframe.style.border = '0';
76
+ iframe.style.width = '0';
77
+ iframe.style.height = '0';
78
+ iframe.style.overflow = 'hidden';
79
+ iframe.addEventListener('load', this[loadHandler]);
80
+ iframe.id = 'oauth2-authorization-frame';
81
+ iframe.setAttribute('data-owner', 'oauth2-authorization');
82
+ iframe.setAttribute('aria-hidden', 'true');
83
+ this[targetValue].appendChild(iframe);
84
+ iframe.src = url;
85
+ this.frame = iframe;
86
+ }
87
+
88
+ /**
89
+ * Handler for the `load` event on the frame.
90
+ * @param {Event} e
91
+ */
92
+ [loadHandler](e: Event): void {
93
+ this.cancel();
94
+ const iframe = e.target as HTMLIFrameElement
95
+ try {
96
+ if (iframe.contentWindow) {
97
+ iframe.contentWindow.addEventListener('unload', () => {
98
+ this.cancel();
99
+ });
100
+ }
101
+ } catch (_) {
102
+ // ...
103
+ }
104
+
105
+ this[timeoutValue] = 8;
106
+ this.loadTimeout = setTimeout(this[checkInterval], this[timeoutValue]);
107
+ }
108
+
109
+ /**
110
+ * A callback function that runs in the timeout.
111
+ * It calls the timeout if the timeout value reaches the limit or increases the timeout value
112
+ * and runs the counter once again.
113
+ */
114
+ [checkInterval](): void {
115
+ if (this.timedOut) {
116
+ return;
117
+ }
118
+ if (this[timeoutValue] >= this[limitValue]) {
119
+ this.cancel();
120
+ this.dispatchEvent(new Event('timeout'));
121
+ this.timedOut = true;
122
+ this.cleanUp();
123
+ return;
124
+ }
125
+ this[timeoutValue] *= 2;
126
+ this.loadTimeout = setTimeout(this[checkInterval], this[timeoutValue]);
127
+ }
128
+ }
@@ -0,0 +1,6 @@
1
+ export const implicit = 'implicit';
2
+ export const code = 'authorization_code';
3
+ export const clientCredentials = 'client_credentials';
4
+ export const password = 'password';
5
+ export const jwtBearer = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
6
+ export const deviceCode = 'urn:ietf:params:oauth:grant-type:device_code';
@@ -0,0 +1,80 @@
1
+ export const observePopupState = Symbol('observePopupState');
2
+ export const popupInterval = Symbol('popupInterval');
3
+ export const popupObserver = Symbol('popupObserver');
4
+ export const intervalValue = Symbol('intervalValue');
5
+
6
+ /**
7
+ * Adds support for the popup window authorization.
8
+ *
9
+ * The set timeout hack is used because I can't see other way of doing this
10
+ * as load/unload events are called only once (even with redirects)
11
+ * and there's no way of knowing what is happening in the popup (so no timeouts).
12
+ * The user may need more time to authorize themselves and then the application.
13
+ *
14
+ * This class dispatches the `close` event when the popup was closed.
15
+ *
16
+ * Call the `cleanUp()` function when the authorization data is received.
17
+ */
18
+ export class PopupAuthorization extends EventTarget {
19
+ [intervalValue]: number;
20
+
21
+ popup?: Window;
22
+
23
+ [popupInterval]: any;
24
+
25
+ /**
26
+ * @param interval The popup state check interval
27
+ */
28
+ constructor(interval = 50) {
29
+ super();
30
+ this[intervalValue] = interval;
31
+ this[popupObserver] = this[popupObserver].bind(this);
32
+ }
33
+
34
+ /**
35
+ * Removes any existing frame and removes any remaining listeners.
36
+ */
37
+ cleanUp(): void {
38
+ if (this[popupInterval]) {
39
+ clearInterval(this[popupInterval]);
40
+ this[popupInterval] = undefined;
41
+ }
42
+ const { popup } = this;
43
+ if (popup && !popup.closed) {
44
+ popup.close();
45
+ }
46
+ this.popup = undefined;
47
+ }
48
+
49
+ /**
50
+ * Opens a popup to request authorization from the user.
51
+ * @param url The URL to open.
52
+ */
53
+ load(url: string): void {
54
+ const op = 'menubar=no,location=no,resizable=yes,scrollbars=yes,status=no,width=800,height=600';
55
+ const popup = window.open(url, 'oauth-window', op);
56
+ if (!popup) {
57
+ throw new Error('Authorization popup is being blocked.');
58
+ }
59
+ popup.window.focus();
60
+ this.popup = popup;
61
+ this[observePopupState]();
62
+ }
63
+
64
+ /**
65
+ * Initializes an interval to check whether the popup window is still present.
66
+ * The web security model does not allow pages to read the URL for the cross domain
67
+ * connections.
68
+ */
69
+ [observePopupState](): void {
70
+ this[popupInterval] = setInterval(this[popupObserver], this[intervalValue]);
71
+ }
72
+
73
+ [popupObserver](): void {
74
+ const { popup } = this;
75
+ if (!popup || popup.closed) {
76
+ this.cleanUp();
77
+ this.dispatchEvent(new Event('close'));
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,124 @@
1
+ import { IOidcTokenInfo, ITokenInfo } from "../../models/Authorization.js";
2
+
3
+ export class Tokens {
4
+ /**
5
+ * Creates a OidcTokenInfo object for the corresponding response type.
6
+ *
7
+ * @param responseType The response type of the token to prepare the info for.
8
+ * @param params params received from the authorization endpoint.
9
+ * @param time Timestamp when the tokens were created
10
+ * @param requestedScopes The list of requested scopes. Optional.
11
+ * @returns
12
+ */
13
+ static createTokenInfo(responseType: string, params: URLSearchParams, time: number, requestedScopes?: string[]): IOidcTokenInfo | null {
14
+ switch (responseType) {
15
+ case 'code': return Tokens.createCodeToken(params, time, requestedScopes);
16
+ case 'token': return Tokens.createTokenToken(params, time, requestedScopes);
17
+ case 'id_token': return Tokens.createIdTokenToken(params, time, requestedScopes);
18
+ default: return null;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Creates a "code" response type token info.
24
+ * @param params
25
+ * @param time Timestamp when the tokens were created
26
+ * @param requestedScopes The list of requested scopes. Optional.
27
+ * @returns
28
+ */
29
+ static createBaseToken(params: URLSearchParams, time: number, requestedScopes?: string[]): IOidcTokenInfo {
30
+ const scope = Tokens.computeTokenInfoScopes(requestedScopes, params.get('scope')!);
31
+ const tokenInfo: IOidcTokenInfo = {
32
+ state: params.get('state')!,
33
+ expiresIn: Number(params.get('expires_in')),
34
+ tokenType: params.get('token_type')!,
35
+ scope,
36
+ time,
37
+ responseType: '',
38
+ };
39
+ return tokenInfo;
40
+ }
41
+
42
+ /**
43
+ * Creates a "code" response type token info.
44
+ * @param params
45
+ * @param time Timestamp when the tokens were created
46
+ * @param requestedScopes The list of requested scopes. Optional.
47
+ * @returns
48
+ */
49
+ static createCodeToken(params: URLSearchParams, time: number, requestedScopes?: string[]): IOidcTokenInfo {
50
+ const token = Tokens.createBaseToken(params, time, requestedScopes);
51
+ token.responseType = 'code';
52
+ token.code = params.get('code')!;
53
+ return token;
54
+ }
55
+
56
+ /**
57
+ * Creates a "token" response type token info.
58
+ * @param params
59
+ * @param time Timestamp when the tokens were created
60
+ * @param requestedScopes The list of requested scopes. Optional.
61
+ * @returns
62
+ */
63
+ static createTokenToken(params: URLSearchParams, time: number, requestedScopes?: string[]): IOidcTokenInfo {
64
+ const token = Tokens.createBaseToken(params, time, requestedScopes);
65
+ token.responseType = 'token';
66
+ token.accessToken = params.get('access_token')!;
67
+ token.refreshToken = params.get('refresh_token')!;
68
+ return token;
69
+ }
70
+
71
+ /**
72
+ * Creates a "id_token" response type token info.
73
+ * @param time Timestamp when the tokens were created
74
+ * @param requestedScopes The list of requested scopes. Optional.
75
+ */
76
+ static createIdTokenToken(params: URLSearchParams, time: number, requestedScopes?: string[]): IOidcTokenInfo {
77
+ const token = Tokens.createBaseToken(params, time, requestedScopes);
78
+ token.responseType = 'id_token';
79
+ token.accessToken = params.get('access_token')!;
80
+ token.refreshToken = params.get('refresh_token')!;
81
+ token.idToken = params.get('id_token')!;
82
+ return token;
83
+ }
84
+
85
+ /**
86
+ * Computes the final list of granted scopes.
87
+ * It is a list of scopes received in the response or the list of requested scopes.
88
+ * Because the user may change the list of scopes during the authorization process
89
+ * the received list of scopes can be different than the one requested by the user.
90
+ *
91
+ * @param requestedScopes The list of requested scopes. Optional.
92
+ * @param tokenScopes The `scope` parameter received with the response. It's null safe.
93
+ * @returns The list of scopes for the token.
94
+ */
95
+ static computeTokenInfoScopes(requestedScopes?: string[], tokenScopes?: string): string[] {
96
+ if (!tokenScopes && requestedScopes) {
97
+ return requestedScopes;
98
+ }
99
+ let listScopes: string[] = [];
100
+ if (typeof tokenScopes === 'string') {
101
+ listScopes = tokenScopes.split(' ');
102
+ }
103
+ return listScopes;
104
+ }
105
+
106
+ static fromTokenInfo(info: ITokenInfo): IOidcTokenInfo {
107
+ const result: IOidcTokenInfo = {
108
+ responseType: '',
109
+ state: info.state,
110
+ accessToken: info.accessToken,
111
+ time: Date.now(),
112
+ };
113
+ if (info.scope) {
114
+ result.scope = info.scope;
115
+ }
116
+ if (info.tokenType) {
117
+ result.tokenType = info.tokenType;
118
+ }
119
+ if (info.expiresIn) {
120
+ result.expiresIn = info.expiresIn;
121
+ }
122
+ return result;
123
+ }
124
+ }