@nsshunt/stsoauth2plugin 0.1.35 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,111 +0,0 @@
1
- export enum AuthorizeOptionsResponseType {
2
- CODE = 'code',
3
- ID_TOKEN = 'id_token',
4
- TOKEN = 'token'
5
- }
6
-
7
- export enum AuthorizeOptionsResponseMode {
8
- QUERY = 'query',
9
- FRAGMENT = 'fragment',
10
- FORM_POST = 'form_post'
11
- }
12
-
13
- // https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
14
- export interface IAuthorizeOptions {
15
- client_id: string,
16
- nonce: string,
17
- response_type: AuthorizeOptionsResponseType[], // Must include: 'code' and may include: 'id_token' and/or 'token'
18
- redirect_uri: string,
19
- response_mode: AuthorizeOptionsResponseMode
20
- scope: string, // A space-separated list of scopes that you want the user to consent to. For the /authorize leg of the request, this parameter can cover multiple resources. This value allows your app to get consent for multiple web APIs you want to call.
21
- state: string, // Client application state (if required)
22
- code_challenge: string,
23
- code_challenge_method: string, //@@ enum S256
24
- code_verifier?: string
25
- }
26
-
27
- export interface IAuthorizeResponse {
28
- state: string, // state passed to authorize end-point
29
- code: string // authorization code
30
- }
31
-
32
- export interface IAuthorizeErrorResponse {
33
- error: string,
34
- error_description: string
35
- }
36
-
37
- export enum OAuthGrantTypes {
38
- CLIENT_CREDENTIALS = 'client_credentials',
39
- AUTHORIZATION_CODE = 'authorization_code',
40
- REFRESH_TOKEN = 'refresh_token'
41
- }
42
-
43
- export interface IAuthorizationCodeFlowParameters {
44
- client_id: string,
45
- scope: string,
46
- code: string,
47
- redirect_uri: string, // URI
48
- grant_type: OAuthGrantTypes, // 'authorization_code', //@@ need enum
49
- code_verifier: string
50
- }
51
-
52
- export interface IRefreshFlowParameters {
53
- client_id: string,
54
- scope: string,
55
- refresh_token: string, // JWT
56
- grant_type: OAuthGrantTypes // 'refresh_token' //@@ enum
57
- }
58
-
59
- export interface ITokenResponse {
60
- access_token: string, // JWT
61
- token_type: string, //@@ "Bearer" only
62
- expires_in: number,
63
- scope: string,
64
- refresh_token: string, // JWT
65
- id_token: string, // JWT
66
- }
67
-
68
- export interface ITokenErrorResponse {
69
- error: string,
70
- error_description: string,
71
- error_codes: number[],
72
- timestamp: number
73
- details: unknown //@@ STS attribute ?
74
- //"trace_id": "255d1aef-8c98-452f-ac51-23d051240864", //@@ MS attribute
75
- //"correlation_id": "fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7" //@@ MS attribute
76
- }
77
-
78
- export type AuthenticateEvent = (id_token: string) => void;
79
-
80
- // ---------------
81
-
82
- export enum IOauth2ListenerCommand {
83
- RESTORE_SESSION = 'RestoreSession',
84
- AUTHORIZE = 'Authorize',
85
- HANDLE_REDIRECT = 'HandleRedirect',
86
- LOGOUT = 'Logout',
87
- AUTHENTICATE_EVENT = 'AuthenticateEvent',
88
- ERROR = 'Error',
89
- LOG = '__LOG',
90
- UPDATE_INSTRUMENT = '__UPDATE_INSTRUMENT'
91
- }
92
-
93
- export interface IOauth2ListenerMessage {
94
- messageId?: number
95
- command: IOauth2ListenerCommand
96
- payload?: any
97
- }
98
-
99
- export interface IOauth2ListenerMessageResponse {
100
- messageId: number
101
- command: IOauth2ListenerCommand
102
- payload: any
103
- }
104
-
105
- export type StsOauth2WorkerFactory = () => Worker
106
-
107
- export interface ISTSOAuth2ManagerOptions {
108
- router: any
109
- authenticateEvent?: AuthenticateEvent
110
- workerFactory?: StsOauth2WorkerFactory
111
- }
@@ -1,583 +0,0 @@
1
- import Debug from "debug";
2
- const debug = Debug(`proc:${process.pid}:stsoauth2worker.ts`);
3
-
4
- //import 'colors'
5
-
6
- import axios from "axios";
7
-
8
- import { JSONObject, OAuth2ParameterType } from '@nsshunt/stsutils';
9
-
10
- import CryptoUtils from './Utils/CryptoUtils'
11
- import QueryParams from './Utils/QueryParams'
12
-
13
- import jwt_decode from "jwt-decode"
14
-
15
- import { IStsStorage, ClientStorageType, ClientStorageFactory } from './stsStorage'
16
-
17
- import { StatusCodes } from 'http-status-codes'
18
-
19
- import { AuthorizeOptionsResponseType, AuthorizeOptionsResponseMode, IAuthorizationCodeFlowParameters, IRefreshFlowParameters,
20
- IAuthorizeOptions, ITokenResponse, IAuthorizeResponse, IAuthorizeErrorResponse, ITokenErrorResponse, OAuthGrantTypes, AuthenticateEvent,
21
- IOauth2ListenerMessage, IOauth2ListenerCommand, IOauth2ListenerMessageResponse } from './stsoauth2types'
22
-
23
- import { Gauge, InstrumentBaseTelemetry, InstrumentLogTelemetry, InstrumentGaugeTelemetry } from '@nsshunt/stsinstrumentation'
24
-
25
- const CreateRandomString = (size = 43) => {
26
- const randomValues = Array.from(self.crypto.getRandomValues(new Uint8Array(size)))
27
- const b64 = window.btoa(String.fromCharCode(...randomValues));
28
- return b64;
29
- //return randomValues.toString('base64');
30
- }
31
-
32
- // STS Client SDK for SPAs
33
- export class STSOAuth2Worker {
34
- //#storageManager = null;
35
- #clientSessionStore: IStsStorage<ITokenResponse> = null; // In memory tokens while the client is logged in
36
- #cUtils = new CryptoUtils();
37
- #qParams = new QueryParams();
38
- #STORAGE_SESSION_KEY = 'session.stsmda.com.au';
39
- #aic = null;
40
- #oauthWorkerPort: MessagePort = null;
41
-
42
- constructor(workerPort: MessagePort) {
43
- //this.#store = app.config.globalProperties.$store;
44
-
45
- // In memory storage for OAuth2 tokens for our valid session
46
- this.#clientSessionStore = new ClientStorageFactory<ITokenResponse>({clientStorageType: ClientStorageType.MEMORY_STORAGE}).GetStorage();
47
-
48
- //@@ needs to be sent the instrument manager controller port
49
- //@@this.#aic = app.config.globalProperties.$sts.aic.PrimaryPublishInstrumentController;
50
-
51
- //this.#handleAuthenticateEvent = handleAuthenticateEvent;
52
-
53
- this.#oauthWorkerPort = workerPort;
54
-
55
- debug(`STSOAuth2Worker:constructor:#oauthWorkerPort: [${JSON.stringify(this.#oauthWorkerPort)}]`);
56
-
57
- this.SetupListener();
58
-
59
- setInterval(() => {
60
- this.#UpdateInstrument(Gauge.LOGGER, {
61
- LogMessage: `--> [${Date.now().toString()}] <--`
62
- } as InstrumentLogTelemetry);
63
-
64
- this.#UpdateInstrument(Gauge.REQUEST_COUNT_GAUGE, {
65
- Inc: 1
66
- } as InstrumentGaugeTelemetry);
67
-
68
- this.#UpdateInstrument(Gauge.AUTHENTICATION_COUNT_GAUGE, {
69
- Inc: 1
70
- } as InstrumentGaugeTelemetry);
71
- }, 1000);
72
- }
73
-
74
- // Attempt to restore a previous session using the STSBroker
75
- /*
76
- { parameterType: OAuth2ParameterType.CLIENT_ID, errorType: authErrorType.CLIENT_ID_MISMATCH },
77
- { parameterType: OAuth2ParameterType.SCOPE, errorType: authErrorType.SCOPE_MISMATCH }
78
- { parameterType: OAuth2ParameterType.REDIRECT_URI, errorType: authErrorType.REDIRECT_URI_MISMATCH },
79
- { parameterType: OAuth2ParameterType.AUDIENCE, errorType: authErrorType.SCOPE_MISMATCH }
80
-
81
- Successful Response
82
- {
83
- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
84
- "token_type": "Bearer",
85
- "expires_in": 3599,
86
- "scope": "https%3A%2F%2Fgraph.microsoft.com%2Fmail.read",
87
- "refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
88
- "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0LTQ2YTctOD...",
89
- }
90
-
91
- Error Response
92
- {
93
- "error": "invalid_scope",
94
- "error_description": "AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope https://foo.microsoft.com/mail.read is not valid.\r\nTrace ID: 255d1aef-8c98-452f-ac51-23d051240864\r\nCorrelation ID: fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7\r\nTimestamp: 2016-01-09 02:02:12Z",
95
- "error_codes": [
96
- 70011
97
- ],
98
- "timestamp": "2016-01-09 02:02:12Z",
99
- }
100
-
101
-
102
- */
103
-
104
- #HandleAuthenticateEvent = (id_token: string) => {
105
- const message: IOauth2ListenerMessage = {
106
- messageId: -1, // un-solicited message
107
- command: IOauth2ListenerCommand.AUTHENTICATE_EVENT
108
- }
109
- this.#ProcessCommand(message, id_token);
110
- }
111
-
112
- #HandleErrorEvent = (error: any) => {
113
- const message: IOauth2ListenerMessage = {
114
- messageId: -1, // un-solicited message
115
- command: IOauth2ListenerCommand.ERROR
116
- }
117
- this.#ProcessCommand(message, error);
118
- }
119
-
120
- #LogMessage = (messageToSend: string) => {
121
- const message: IOauth2ListenerMessage = {
122
- messageId: -1, // un-solicited message
123
- command: IOauth2ListenerCommand.LOG
124
- }
125
- this.#ProcessCommand(message, messageToSend);
126
- }
127
-
128
- #UpdateInstrument = (instrumentName: Gauge, telemetry: InstrumentBaseTelemetry): void => {
129
- const message: IOauth2ListenerMessage = {
130
- messageId: -1, // un-solicited message
131
- command: IOauth2ListenerCommand.UPDATE_INSTRUMENT
132
- }
133
- this.#ProcessCommand(message, {
134
- instrumentName,
135
- telemetry
136
- });
137
- }
138
-
139
- SetupListener = () => {
140
- this.#oauthWorkerPort.onmessage = async (data: MessageEvent) => {
141
- const auth2ListenerMessage: IOauth2ListenerMessage = data.data as IOauth2ListenerMessage;
142
- switch (auth2ListenerMessage.command) {
143
- case IOauth2ListenerCommand.RESTORE_SESSION :
144
- this.#ProcessCommand(auth2ListenerMessage, await this.#RestoreSession());
145
- break;
146
- case IOauth2ListenerCommand.AUTHORIZE :
147
- this.#ProcessCommand(auth2ListenerMessage, await this.#Authorize());
148
- break;
149
- case IOauth2ListenerCommand.HANDLE_REDIRECT :
150
- this.#ProcessCommand(auth2ListenerMessage, await this.#HandleRedirect(auth2ListenerMessage.payload));
151
- break;
152
- case IOauth2ListenerCommand.LOGOUT :
153
- this.#ProcessCommand(auth2ListenerMessage, await this.#Logout());
154
- break;
155
- default :
156
- throw new Error(`Command: [${auth2ListenerMessage.command}'] not found.`);
157
- }
158
- }
159
- }
160
-
161
- #ProcessCommand = async (auth2ListenerMessage: IOauth2ListenerMessage, response: any) => {
162
- const messageResponse: IOauth2ListenerMessageResponse = {
163
- messageId: auth2ListenerMessage.messageId,
164
- command: auth2ListenerMessage.command,
165
- payload: response
166
- }
167
-
168
- debug(`STSOAuth2Worker:ProcessCommand:#oauthWorkerPort: [${JSON.stringify(this.#oauthWorkerPort)}]`);
169
- debug(this);
170
-
171
- this.#oauthWorkerPort.postMessage(messageResponse);
172
- }
173
-
174
- #RestoreSession = async (): Promise<boolean> => {
175
- //@@ attempt to get from client storage first
176
-
177
- let restoredSessionData: ITokenResponse = null;
178
- restoredSessionData = this.#clientSessionStore.get(this.#STORAGE_SESSION_KEY);
179
- if (restoredSessionData !== null) {
180
- console.log('Session restored from client storage.');
181
- if (this.#aic) {
182
- this.#aic.UpdateInstrument('m', { LogMessage: 'Session restored from client storage.' });
183
- }
184
- this.#LogMessage('Session restored from client storage.')
185
- } else {
186
- const url = `${process.env.BROKER_ENDPOINT}:${process.env.BROKER_PORT}${process.env.BROKER_API_ROOT}/session`;
187
- console.log('RestoreSession');
188
- console.log(url);
189
- if (this.#aic) {
190
- this.#aic.UpdateInstrument('m', { LogMessage: 'RestoreSession' });
191
- this.#aic.UpdateInstrument('m', { LogMessage: url });
192
- }
193
- this.#LogMessage('RestoreSession.');
194
- this.#LogMessage(url);
195
- try {
196
- const retVal = await axios({
197
- method: "post",
198
- url: url,
199
- data: {
200
- [OAuth2ParameterType.CLIENT_ID]: process.env.CLIENT_ID,
201
- [OAuth2ParameterType.SCOPE]: process.env.SCOPE,
202
- [OAuth2ParameterType.REDIRECT_URI]: process.env.REDIRECT_URI,
203
- [OAuth2ParameterType.AUDIENCE]: process.env.AUDIENCE
204
- },
205
- withCredentials: true, // Ensure cookies are passed to the service
206
- timeout: parseInt(process.env.TIMEOUT),
207
- });
208
- if (retVal.data.status === StatusCodes.OK) {
209
- restoredSessionData = retVal.data.detail;
210
- this.#clientSessionStore.set(this.#STORAGE_SESSION_KEY, restoredSessionData);
211
- console.log('Session restored from server side cookie.');
212
- //this.#store.commit('stsOAuth2SDK/SessionData', restoredSessionData);
213
- } else {
214
- //@@ handle error better
215
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
216
- console.log('Could not restore previous session:-');
217
- console.log(JSON.stringify(retVal.data));
218
- }
219
- } catch (error) {
220
- //@@ handle error better
221
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
222
- console.log('Could not restore previous session (error state):-');
223
- console.log(error);
224
- console.log(JSON.stringify(error));
225
- }
226
- }
227
-
228
- //@@ must only use in-memory for this ...
229
- //this.#store.commit('stsOAuth2SDK/SessionData', restoredSessionData);
230
- if (restoredSessionData !== null) {
231
- this.#HandleAuthenticateEvent(restoredSessionData.id_token);
232
- console.log('Refreshing tokens ...');
233
- return this.#RefreshToken();
234
- } else {
235
- this.#HandleAuthenticateEvent(null);
236
- return false;
237
- }
238
- }
239
-
240
- #Authorize = async (): Promise<JSONObject> => {
241
- console.log('Authorize ...');
242
-
243
- /* MS Example
244
- --------------
245
- https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
246
- client_id=6731de76-14a6-49ae-97bc-6eba6914391e
247
- &response_type=code
248
- &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
249
- &response_mode=query
250
- &scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read%20api%3A%2F%2F
251
- &state=12345
252
- &code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
253
- &code_challenge_method=S256
254
-
255
- Successful Response
256
-
257
- GET http://localhost?
258
- code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrq...
259
- &state=12345
260
-
261
- Error Response
262
- GET http://localhost?
263
- error=access_denied
264
- &error_description=the+user+canceled+the+authentication
265
-
266
- << Hybrid Flow >>
267
-
268
- https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
269
- client_id=6731de76-14a6-49ae-97bc-6eba6914391e
270
- &response_type=code%20id_token
271
- &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
272
- &response_mode=fragment
273
- &scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read
274
- &state=12345
275
- &nonce=abcde
276
- &code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
277
- &code_challenge_method=S256
278
-
279
- Successful Response
280
-
281
- GET https://login.microsoftonline.com/common/oauth2/nativeclient#
282
- code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrq...
283
- &id_token=eYj...
284
- &state=12345
285
-
286
- Notes:
287
- The nonce is included as a claim inside the returned id_token
288
- Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
289
- */
290
-
291
- const client_id = process.env.CLIENT_ID;
292
- const nonce = this.#cUtils.CreateRandomString();
293
- const response_type = [ AuthorizeOptionsResponseType.CODE ]
294
- const redirect_uri = process.env.REDIRECT_URI;
295
- const response_mode = AuthorizeOptionsResponseMode.QUERY
296
- const scope = process.env.SCOPE;
297
- const state = this.#cUtils.CreateRandomString();
298
- const code_verifier = this.#cUtils.CreateRandomString();
299
- const code_challenge = await this.#cUtils.DigestMessage(code_verifier);
300
- const code_challenge_method = 'S256';
301
- //let audience = process.env.AUDIENCE;
302
-
303
- const authorizeOptions: IAuthorizeOptions = {
304
- client_id,
305
- nonce,
306
- response_type,
307
- redirect_uri,
308
- response_mode,
309
- scope,
310
- state,
311
- code_challenge,
312
- code_challenge_method
313
- }
314
-
315
- const url = `${process.env.AUTH_ENDPOINT}:${process.env.AUTH_PORT}${process.env.AUTH_APIROOT}?${this.#qParams.CreateQueryParams(authorizeOptions)}`;
316
-
317
- console.log(url);
318
-
319
- // Now add the code_verifier to the transaction data
320
- authorizeOptions.code_verifier = code_verifier; //@@ Is this is the only thing required across the transaction ?
321
-
322
- console.log(`Authorize:authorizeOptions: [${JSON.stringify(authorizeOptions)}]`);
323
-
324
- return {
325
- url,
326
- authorizeOptions
327
- }
328
- //window.location.assign(url);
329
- //@@ this may need to be a message back to the plugin to re-direct
330
- //window.location.replace(url);
331
- }
332
-
333
- #HandleRedirect = async (payload: any): Promise<boolean> => {
334
- const queryVars: IAuthorizeResponse | IAuthorizeErrorResponse = payload.queryVars;
335
- const authorizeOptions: IAuthorizeOptions = payload.authorizeOptions
336
-
337
- console.log('HandleRedirect');
338
- // We have been re-direct back here from the /authorize end-point
339
- console.log(`HandleRedirect:Query Vars: [${JSON.stringify(queryVars)}]`);
340
-
341
- if (queryVars[OAuth2ParameterType.CODE]) {
342
- const response: IAuthorizeResponse = queryVars as IAuthorizeResponse;
343
-
344
- console.log(`authorizeOptions from transaction state: [${JSON.stringify(authorizeOptions)}]`);
345
-
346
- const redirectState = response.state;
347
- const authorizeOptionsState = authorizeOptions.state;
348
-
349
- if (authorizeOptionsState.localeCompare(redirectState) === 0) {
350
- console.log('redirected state (from queryVars) matched previously saved transaction authorizeOptions state'); // green
351
-
352
- return await this.#GetToken(authorizeOptions, response);
353
- } else {
354
- console.log('redirected state (from queryVars) did NOT match previously saved transaction authorizeOptions state'); // red
355
- this.#HandleErrorEvent({message: 'State un-matched'});
356
- return false;
357
- }
358
- } else if (queryVars[OAuth2ParameterType.ERROR]) {
359
- const response: IAuthorizeErrorResponse = queryVars as IAuthorizeErrorResponse;
360
- //@@ pass error back to parent thread (to the plugin) as a message
361
- const error = response.error;
362
- const errorDescription = response.error_description;
363
- this.#HandleErrorEvent({message: 'State un-matched'});
364
- return false;
365
- } else {
366
- // Invalid redirect query params
367
- const error = 'Invalid redirect query params'; //@@ fix
368
- const errorDescription = 'Invalid redirect query params description'; //@@ fix
369
- this.#HandleErrorEvent({message: 'State un-matched'});
370
- return false;
371
- }
372
- }
373
-
374
- /*
375
- client_id=6731de76-14a6-49ae-97bc-6eba6914391e
376
- &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
377
- &code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
378
- &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
379
- &grant_type=authorization_code
380
- &code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong
381
- &client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps. This secret needs to be URL-Encoded.
382
-
383
- Successful Response
384
- {
385
- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
386
- "token_type": "Bearer",
387
- "expires_in": 3599,
388
- "scope": "https%3A%2F%2Fgraph.microsoft.com%2Fmail.read",
389
- "refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
390
- "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdWQiOiIyZDRkMTFhMi1mODE0LTQ2YTctOD...",
391
- }
392
- */
393
-
394
- // Get access_token, refresh_token and id_token using OAuth2 Authorization Code Flow
395
- #GetTokenFromBroker = async (authorizationCodeFlowParameters: IAuthorizationCodeFlowParameters | IRefreshFlowParameters): Promise<boolean> => {
396
- console.log("#GetTokenFromBroker");
397
-
398
- this.#clientSessionStore.remove(this.#STORAGE_SESSION_KEY);
399
-
400
- const url = `${process.env.BROKER_ENDPOINT}:${process.env.BROKER_PORT}${process.env.BROKER_API_ROOT}/token`;
401
- console.log(`#GetTokenFromBroker:url = [${url}]`);
402
- console.log(authorizationCodeFlowParameters);
403
-
404
- try {
405
- const retVal = await axios({
406
- method: "post",
407
- url: url,
408
- data: authorizationCodeFlowParameters,
409
- withCredentials: true, // Ensure cookies are passed to the service
410
- timeout: parseInt(process.env.TIMEOUT),
411
- });
412
- console.log(`retVal: ${JSON.stringify(retVal)}`);
413
-
414
- if (retVal.status === StatusCodes.OK) {
415
- console.log('Storing tokens...');
416
- const tokenResponse: ITokenResponse = retVal.data as ITokenResponse;
417
- //this.#store.commit('stsOAuth2SDK/SessionData', tokenResponse);
418
- this.#HandleAuthenticateEvent(tokenResponse.id_token);
419
- this.#clientSessionStore.set(this.#STORAGE_SESSION_KEY, tokenResponse);
420
- return true;
421
- } else if (retVal.status === StatusCodes.UNAUTHORIZED) {
422
- console.log('NOT Storing tokens...');
423
- console.log(retVal.status);
424
-
425
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
426
- this.#HandleAuthenticateEvent(null);
427
-
428
- const response: ITokenErrorResponse = retVal.data as ITokenErrorResponse;
429
-
430
- //@@ store response in state
431
- //@@ go to error page ??
432
- return false;
433
-
434
- } else {
435
- // General error
436
- console.log('NOT Storing tokens...');
437
- console.log(retVal.status);
438
-
439
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
440
- this.#HandleAuthenticateEvent(null);
441
-
442
- console.log('Could not obtain access_token from token end-point:-');
443
- console.log(JSON.stringify(retVal.data));
444
- //@@ store error in state to show in error page
445
- return false;
446
- }
447
- } catch (error) {
448
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
449
- this.#HandleAuthenticateEvent(null);
450
- //console.log('Could not restore previous session (error state):-');
451
- console.log(error);
452
- console.log(JSON.stringify(error));
453
-
454
- //@@ store error in state to show in error page
455
-
456
- return false;
457
- }
458
- }
459
-
460
- // Get access_token, refresh_token and id_token using OAuth2 Authorization Code Flow
461
- #GetToken = async (authorizeOptions: IAuthorizeOptions, authorizeResponse: IAuthorizeResponse): Promise<boolean> => {
462
- console.log("#GetToken");
463
- console.log(authorizeResponse);
464
-
465
- this.#clientSessionStore.set(this.#STORAGE_SESSION_KEY, null);
466
-
467
- const authorizationCodeFlowParameters: IAuthorizationCodeFlowParameters = {
468
- client_id: process.env.CLIENT_ID,
469
- scope: process.env.SCOPE,
470
- code: authorizeResponse.code,
471
- redirect_uri: process.env.REDIRECT_URI,
472
- grant_type: OAuthGrantTypes.AUTHORIZATION_CODE,
473
- code_verifier: authorizeOptions.code_verifier
474
- }
475
-
476
- return this.#GetTokenFromBroker(authorizationCodeFlowParameters);
477
- }
478
-
479
- /*
480
- // Line breaks for legibility only
481
-
482
- POST /{tenant}/oauth2/v2.0/token HTTP/1.1
483
- Host: https://login.microsoftonline.com
484
- Content-Type: application/x-www-form-urlencoded
485
-
486
- client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
487
- &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
488
- &refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
489
- &grant_type=refresh_token
490
- &client_secret=sampleCredentia1s // NOTE: Only required for web apps. This secret needs to be URL-Encoded
491
-
492
- Error Response
493
- {
494
- "error": "invalid_scope",
495
- "error_description": "AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope https://foo.microsoft.com/mail.read is not valid.\r\nTrace ID: 255d1aef-8c98-452f-ac51-23d051240864\r\nCorrelation ID: fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7\r\nTimestamp: 2016-01-09 02:02:12Z",
496
- "error_codes": [
497
- 70011
498
- ],
499
- "timestamp": "2016-01-09 02:02:12Z",
500
- "trace_id": "255d1aef-8c98-452f-ac51-23d051240864",
501
- "correlation_id": "fb3d2015-bc17-4bb9-bb85-30c5cf1aaaa7"
502
- }
503
- */
504
-
505
- #RefreshToken = async (): Promise<boolean> => {
506
- // Get access_token, refresh_token and id_token using OAuth2 Authorization Code Flow
507
- console.log("RefreshToken");
508
-
509
- //let currentSessionData = this.#store.getters['stsOAuth2SDK/SessionData'];
510
- const currentSessionData: ITokenResponse = this.#clientSessionStore.get(this.#STORAGE_SESSION_KEY);
511
- if (currentSessionData) {
512
- const refreshFlowParameters: IRefreshFlowParameters = {
513
- client_id: process.env.CLIENT_ID,
514
- scope: process.env.SCOPE,
515
- refresh_token: currentSessionData.refresh_token,
516
- grant_type: OAuthGrantTypes.REFRESH_TOKEN
517
- }
518
-
519
- return this.#GetTokenFromBroker(refreshFlowParameters);
520
- } else {
521
- // show error
522
- //@@ no valid session exists for refresh
523
- return false;
524
- }
525
- }
526
-
527
- // call broker to logout
528
- // broker to logout of server
529
- // delete cookie
530
- // clear session storage
531
- // clear all state from $store
532
- #Logout = async (): Promise<boolean> => {
533
- console.log('Logout');
534
- const url = `${process.env.BROKER_ENDPOINT}:${process.env.BROKER_PORT}${process.env.BROKER_API_ROOT}/logout`;
535
- console.log(url);
536
-
537
- const currentSessionData: ITokenResponse = this.#clientSessionStore.get(this.#STORAGE_SESSION_KEY);
538
- const refresh_token = currentSessionData.refresh_token;
539
- console.log(refresh_token);
540
-
541
- const decodedRefreshToken: JSONObject = jwt_decode<JSONObject>(refresh_token);
542
- console.log(decodedRefreshToken);
543
- const sessionId = decodedRefreshToken.sts_session;
544
- console.log(sessionId);
545
-
546
- this.#clientSessionStore.remove(this.#STORAGE_SESSION_KEY);
547
- //this.#store.commit('stsOAuth2SDK/SessionData', null);
548
- this.#HandleAuthenticateEvent(null);
549
-
550
- try {
551
- const retVal = await axios({
552
- method: "post",
553
- url: url,
554
- data: {
555
- sessionId
556
- },
557
- withCredentials: true, // Ensure cookies are passed to the service
558
- timeout: parseInt(process.env.TIMEOUT),
559
- });
560
- if (retVal.data.status === StatusCodes.OK) {
561
- return true;
562
- } else {
563
- console.log('Error during logout (server side)');
564
- console.log(JSON.stringify(retVal.data));
565
- return false;
566
- }
567
- } catch (error) {
568
- console.log('Error during logout (server side)');
569
- console.log(error);
570
- console.log(JSON.stringify(error));
571
- return false;
572
- }
573
- }
574
- }
575
- /*
576
- let oAuth2Worker: STSOAuth2Worker = null;
577
-
578
- onmessage = async function(data: MessageEvent)
579
- {
580
- const workerPort = data.data as MessagePort;
581
- oAuth2Worker = new STSOAuth2Worker(workerPort);
582
- }
583
- */