Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/api/src/modules/summary/summary.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { QueryOptionsDto } from 'src/common/graphql/dtos/query-options.dto';
import { SummaryResponse } from './dto/summary-response.dto';
import { UseGuards } from '@nestjs/common';
import { AzureADGuard } from 'src/auth/azure-ad.guard';
import { CurrentUser } from 'src/Decorator/user.decorator';
import { CurrentUser } from 'src/common/decorators/user.decorator';

@Resolver(() => Summary)
export class SummaryResolver {
Expand Down
4 changes: 0 additions & 4 deletions apps/portal/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export class AppComponent implements OnInit, OnDestroy {
.subscribe((result: EventMessage) => {
const payload = result.payload as AuthenticationResult;
this.authService.instance.setActiveAccount(payload.account);
sessionStorage.setItem('accessToken', payload.accessToken);
this.setLoginDisplay();
});

Expand Down Expand Up @@ -89,9 +88,6 @@ export class AppComponent implements OnInit, OnDestroy {

if (account) {
this.authService.acquireTokenSilent({ scopes, account }).subscribe({
next: (tokenResponse: AuthenticationResult) => {
sessionStorage.setItem('accessToken', tokenResponse.accessToken);
},
error: () => {
// Fallback to interactive method if silent fails
this.authService.acquireTokenRedirect({ scopes });
Expand Down
111 changes: 72 additions & 39 deletions apps/portal/src/app/graphql/graphql.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { DocumentNode } from 'graphql';
import { QueryRef, Apollo, MutationResult } from 'apollo-angular';
import { Observable, throwError } from 'rxjs';
import { ApolloQueryResult } from '@apollo/client';
import { catchError } from 'rxjs/operators';
import { catchError, switchMap } from 'rxjs/operators';
import { MsalService } from '@azure/msal-angular';
import { AuthenticationResult, InteractionRequiredAuthError } from '@azure/msal-browser';
import { environment } from '../../environments/environment';

@Injectable({
providedIn: 'root',
Expand All @@ -15,8 +17,37 @@ export class GraphqlService {
private authService: MsalService,
) {}

private getToken(): string | null {
return sessionStorage.getItem('accessToken');
private getToken(): Observable<string> {
const account =
this.authService.instance.getActiveAccount() || this.authService.instance.getAllAccounts()[0];

if (!account) {
// eslint-disable-next-line prefer-promise-reject-errors
return throwError('No active account found');
}

const request = {
scopes: [environment.apiScope],
account,
};
const token = this.authService.acquireTokenSilent(request).pipe(
switchMap((response: AuthenticationResult) => {
if (response && response.accessToken) {
return [response.accessToken];
}

return throwError('Failed to acquire token');
}),
catchError((error) => {
if (error instanceof InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
this.authService.acquireTokenRedirect(request);
}

return throwError(error);
}),
);
return token;
}

private handleUnauthorizedError(): void {
Expand All @@ -26,19 +57,21 @@ export class GraphqlService {
}

query<T>(query: DocumentNode): Observable<ApolloQueryResult<T>> {
const token = this.getToken();
const queryRef: QueryRef<T> = this.apollo.use('default').watchQuery({
query,
errorPolicy: 'all',
fetchPolicy: 'network-only',
context: {
headers: {
Authorization: `Bearer ${token}`,
},
},
});
return this.getToken().pipe(
switchMap((token: string) => {
const queryRef: QueryRef<T> = this.apollo.use('default').watchQuery({
query,
errorPolicy: 'all',
fetchPolicy: 'network-only',
context: {
headers: {
Authorization: `Bearer ${token}`,
},
},
});

return queryRef.valueChanges.pipe(
return queryRef.valueChanges;
}),
catchError((error) => {
if (this.isUnauthorizedError(error)) {
this.handleUnauthorizedError();
Expand All @@ -51,32 +84,32 @@ export class GraphqlService {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
mutate<T>(mutation: DocumentNode, variables: any): Observable<MutationResult<T>> {
const token = this.getToken();
return this.apollo
.mutate<T>({
mutation,
variables: { file: variables.inputFile },
context: {
hasUpload: true,
useMultipart: true,
headers: {
'content-type': 'application/json',
'x-apollo-operation-name': 'createSummary',
Authorization: `Bearer ${token}`,
return this.getToken().pipe(
switchMap((token: string) =>
this.apollo.mutate<T>({
mutation,
variables: { file: variables.inputFile },
context: {
hasUpload: true,
useMultipart: true,
headers: {
'content-type': 'application/json',
'x-apollo-operation-name': 'createSummary',
Authorization: `Bearer ${token}`,
},
},
},
errorPolicy: 'all',
fetchPolicy: 'network-only',
})
.pipe(
catchError((error) => {
if (this.isUnauthorizedError(error)) {
this.handleUnauthorizedError();
}

return throwError(error);
errorPolicy: 'all',
fetchPolicy: 'network-only',
}),
);
),
catchError((error) => {
if (this.isUnauthorizedError(error)) {
this.handleUnauthorizedError();
}

return throwError(error);
}),
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down