From 1bc28929c6e880a5b05a885c6dfe35b909170118 Mon Sep 17 00:00:00 2001
From: Steve Reis <stevereis93@gmail.com>
Date: Fri, 25 Mar 2022 18:44:37 +0000
Subject: [PATCH] fix: Logout issue when user can not be retrieve fix: Format
 graphql errors fix: User undefined cause exception in users module fix:
 Active user datashield and fix tos case senstive

---
 api/.env.defaults                             |   3 +
 api/assets/engines/datashield/logo.png        | Bin 0 -> 6534 bytes
 api/package.json                              |   4 +-
 api/src/auth/auth-constants.ts                |   1 +
 api/src/auth/auth.module.ts                   |   4 +-
 api/src/auth/auth.resolver.ts                 |   8 +-
 api/src/auth/auth.service.ts                  |   5 +
 api/src/auth/decorators/public.decorator.ts   |   2 +
 api/src/auth/guards/jwt-auth.guard.ts         |  15 ++-
 .../common/interfaces/utilities.interface.ts  |  13 ---
 api/src/common/utilities.spec.ts              |  95 ++++++++++++++++++
 api/src/common/utilities.ts                   |  32 ++++--
 .../connectors/datashield/main.connector.ts   |  19 ++--
 .../connectors/exareme/main.connector.ts      |   2 +-
 api/src/engine/engine.constants.ts            |   1 +
 api/src/engine/engine.controller.ts           |  27 +----
 api/src/engine/engine.interfaces.ts           |   2 +-
 api/src/engine/engine.module.ts               |   3 -
 api/src/engine/engine.resolver.ts             |  24 ++++-
 .../engine/interceptors/errors.interceptor.ts |   4 +-
 api/src/engine/models/configuration.model.ts  |  11 +-
 .../models/result/table-result.model.ts       |   2 +-
 api/src/main/app.module.ts                    |  14 +++
 api/src/schema.gql                            |   7 +-
 api/src/users/users.resolver.spec.ts          |   8 ++
 api/src/users/users.resolver.ts               |   8 +-
 26 files changed, 233 insertions(+), 81 deletions(-)
 create mode 100644 api/assets/engines/datashield/logo.png
 create mode 100644 api/src/auth/decorators/public.decorator.ts
 create mode 100644 api/src/common/utilities.spec.ts

diff --git a/api/.env.defaults b/api/.env.defaults
index 8fb46c2..ec63f00 100644
--- a/api/.env.defaults
+++ b/api/.env.defaults
@@ -2,6 +2,9 @@
 ENGINE_TYPE=exareme
 ENGINE_BASE_URL=http://127.0.0.1:8080/services/
 
+# GLOBAL
+TOS_SKIP=false
+
 # SERVER
 GATEWAY_PORT=8081
 
diff --git a/api/assets/engines/datashield/logo.png b/api/assets/engines/datashield/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..19885d0405d59e2447045061a3d85fdf88dc7af1
GIT binary patch
literal 6534
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
C6@pj*

literal 0
HcmV?d00001

diff --git a/api/package.json b/api/package.json
index b0a16f8..142d29f 100644
--- a/api/package.json
+++ b/api/package.json
@@ -100,8 +100,8 @@
       "!**/*.decorator.ts",
       "!**/*.model.ts", 
       "!**/*.input.ts", 
-      "!src/jest.config.js",
-      "!src/main.js"
+      "!**/jest.config.ts",
+      "!**/main.ts"
     ],
     "coverageDirectory": "../coverage",
     "testEnvironment": "node"
diff --git a/api/src/auth/auth-constants.ts b/api/src/auth/auth-constants.ts
index c904d45..5e4748c 100644
--- a/api/src/auth/auth-constants.ts
+++ b/api/src/auth/auth-constants.ts
@@ -2,6 +2,7 @@ export const authConstants = {
   JWTSecret: 'AUTH_JWT_SECRET',
   skipAuth: 'AUTH_SKIP',
   expiresIn: 'AUTH_JWT_TOKEN_EXPIRES_IN',
+  enableSSO: 'AUTH_ENABLE_SSO',
   cookie: {
     name: 'jwt-gateway',
     sameSite: 'AUTH_COOKIE_SAME_SITE',
diff --git a/api/src/auth/auth.module.ts b/api/src/auth/auth.module.ts
index 3a5381e..805f0dc 100644
--- a/api/src/auth/auth.module.ts
+++ b/api/src/auth/auth.module.ts
@@ -17,9 +17,9 @@ import { LocalStrategy } from './strategies/local.strategy';
     JwtModule.registerAsync({
       imports: [ConfigModule],
       useFactory: async (configService: ConfigService) => ({
-        secret: configService.get<string>(authConstants.JWTSecret),
+        secret: configService.get(authConstants.JWTSecret),
         signOptions: {
-          expiresIn: configService.get<string>(authConstants.expiresIn),
+          expiresIn: configService.get(authConstants.expiresIn, '2d'),
         },
       }),
       inject: [ConfigService],
diff --git a/api/src/auth/auth.resolver.ts b/api/src/auth/auth.resolver.ts
index 5853fe0..228943e 100644
--- a/api/src/auth/auth.resolver.ts
+++ b/api/src/auth/auth.resolver.ts
@@ -7,18 +7,18 @@ import {
 import { ConfigService } from '@nestjs/config';
 import { Args, Mutation, Resolver } from '@nestjs/graphql';
 import { Response } from 'express';
-import { parseToBoolean } from '../common/interfaces/utilities.interface';
+import { GQLResponse } from '../common/decorators/gql-response.decoractor';
+import { parseToBoolean } from '../common/utilities';
 import { ENGINE_SERVICE } from '../engine/engine.constants';
 import { IEngineService } from '../engine/engine.interfaces';
+import { User } from '../users/models/user.model';
 import { authConstants } from './auth-constants';
 import { AuthService } from './auth.service';
 import { CurrentUser } from './decorators/user.decorator';
 import { JwtAuthGuard } from './guards/jwt-auth.guard';
 import { LocalAuthGuard } from './guards/local-auth.guard';
 import { AuthenticationInput } from './inputs/authentication.input';
-import { User } from '../users/models/user.model';
 import { AuthenticationOutput } from './outputs/authentication.output';
-import { GQLResponse } from '../common/decorators/gql-response.decoractor';
 
 //Custom defined type because Pick<CookieOptions, 'sameSite'> does not work
 type SameSiteType = boolean | 'lax' | 'strict' | 'none' | undefined;
@@ -69,7 +69,7 @@ export class AuthResolver {
   @Mutation(() => Boolean)
   @UseGuards(JwtAuthGuard)
   logout(@GQLResponse() res: Response, @CurrentUser() user: User): boolean {
-    this.logger.verbose(`${user.username} logged out`);
+    if (user) this.logger.verbose(`${user.username} logged out`);
 
     res.clearCookie(authConstants.cookie.name);
     this.engineService.logout?.();
diff --git a/api/src/auth/auth.service.ts b/api/src/auth/auth.service.ts
index 2c09c5b..18eaadf 100644
--- a/api/src/auth/auth.service.ts
+++ b/api/src/auth/auth.service.ts
@@ -17,6 +17,11 @@ export class AuthService {
     return await this.engineService.login?.(username, password);
   }
 
+  /**
+   * It takes a user and returns an access token
+   * @param {User} user - The user object that is being authenticated.
+   * @returns An object with an accessToken property.
+   */
   async login(user: User): Promise<Pick<AuthenticationOutput, 'accessToken'>> {
     const payload = { username: user.username, sub: user };
     return Promise.resolve({
diff --git a/api/src/auth/decorators/public.decorator.ts b/api/src/auth/decorators/public.decorator.ts
new file mode 100644
index 0000000..466abc7
--- /dev/null
+++ b/api/src/auth/decorators/public.decorator.ts
@@ -0,0 +1,2 @@
+import { SetMetadata } from '@nestjs/common';
+export const Public = () => SetMetadata('isPublic', true);
diff --git a/api/src/auth/guards/jwt-auth.guard.ts b/api/src/auth/guards/jwt-auth.guard.ts
index 4afaca5..2ee1a63 100644
--- a/api/src/auth/guards/jwt-auth.guard.ts
+++ b/api/src/auth/guards/jwt-auth.guard.ts
@@ -1,14 +1,18 @@
 import { ExecutionContext, Injectable } from '@nestjs/common';
 import { ConfigService } from '@nestjs/config';
+import { Reflector } from '@nestjs/core';
 import { GqlExecutionContext } from '@nestjs/graphql';
 import { AuthGuard } from '@nestjs/passport';
 import { Observable } from 'rxjs';
-import { parseToBoolean } from '../../common/interfaces/utilities.interface';
+import { parseToBoolean } from '../../common/utilities';
 import { authConstants } from '../auth-constants';
 
 @Injectable()
 export class JwtAuthGuard extends AuthGuard(['jwt-cookies', 'jwt-bearer']) {
-  constructor(private readonly configService: ConfigService) {
+  constructor(
+    private readonly configService: ConfigService,
+    private readonly reflector: Reflector,
+  ) {
     super();
   }
 
@@ -22,11 +26,16 @@ export class JwtAuthGuard extends AuthGuard(['jwt-cookies', 'jwt-bearer']) {
   canActivate(
     context: ExecutionContext,
   ): boolean | Promise<boolean> | Observable<boolean> {
+    const isPublic = this.reflector.get<boolean>(
+      'isPublic',
+      context.getHandler(),
+    );
+
     const skipAuth = parseToBoolean(
       this.configService.get(authConstants.skipAuth, 'false'),
     );
 
-    if (skipAuth) {
+    if (skipAuth || isPublic) {
       return true;
     }
 
diff --git a/api/src/common/interfaces/utilities.interface.ts b/api/src/common/interfaces/utilities.interface.ts
index 762534a..db02ef9 100644
--- a/api/src/common/interfaces/utilities.interface.ts
+++ b/api/src/common/interfaces/utilities.interface.ts
@@ -16,16 +16,3 @@ export enum MIME_TYPES {
   HTML = 'text/html',
   TEXT = 'text/plain',
 }
-
-/**
- * Utility method to convert string value to boolean
- * @param value string value to be converted
- * @returns true if string value equals to 'true', false otherwise
- */
-export const parseToBoolean = (value: string): boolean => {
-  try {
-    return value.toLowerCase() == 'true';
-  } catch {
-    return false;
-  }
-};
diff --git a/api/src/common/utilities.spec.ts b/api/src/common/utilities.spec.ts
new file mode 100644
index 0000000..88f5fb3
--- /dev/null
+++ b/api/src/common/utilities.spec.ts
@@ -0,0 +1,95 @@
+import {
+  HttpException,
+  InternalServerErrorException,
+  NotFoundException,
+  RequestTimeoutException,
+  UnauthorizedException,
+} from '@nestjs/common';
+import axios from 'axios';
+import { response } from 'express';
+import { errorAxiosHandler, parseToBoolean } from './utilities';
+
+describe('Utility parseToBoolean testing', () => {
+  it('Parse true string to boolean', () => {
+    expect(parseToBoolean('true')).toBe(true);
+  });
+
+  it('Parse false string to boolean', () => {
+    expect(parseToBoolean('false')).toBe(false);
+  });
+
+  it('Parse wrong string to boolean, should fallback to false', () => {
+    expect(parseToBoolean('truee')).toBe(false);
+  });
+
+  it('Parse wrong string to boolean, should fallback to false', () => {
+    expect(parseToBoolean('falseee')).toBe(false);
+  });
+
+  it('Parse wrong string to boolean, should fallback to default value', () => {
+    expect(parseToBoolean('trueee', true)).toBe(true);
+  });
+
+  it('Parse empty string to boolean, should fallback to false', () => {
+    expect(parseToBoolean('')).toBe(false);
+  });
+
+  it('Parse true uppercased string to boolean', () => {
+    expect(parseToBoolean('TRUE')).toBe(true);
+  });
+
+  it('Parse false uppercased string to boolean', () => {
+    expect(parseToBoolean('FALSE')).toBe(false);
+  });
+});
+
+jest.mock('axios');
+
+describe('Utility error handling testing', () => {
+  const error = {
+    response: {
+      status: 401,
+      data: 'Dummmy Data',
+    },
+  };
+
+  beforeAll(() => {
+    // eslint-disable-next-line
+    // @ts-ignore
+    axios.isAxiosError.mockReturnValue(true).mockReturnValueOnce(false);
+  });
+
+  afterAll(() => {
+    jest.resetModules();
+  });
+
+  it('Throw internal error', () => {
+    expect(() => errorAxiosHandler(error)).toThrow(
+      InternalServerErrorException,
+    );
+  });
+
+  [
+    { code: 401, type: UnauthorizedException },
+    { code: 404, type: NotFoundException },
+    { code: 408, type: RequestTimeoutException },
+    { code: 500, type: InternalServerErrorException },
+  ].forEach((errorIt) => {
+    it(`Throw ${errorIt.code} error`, () => {
+      error.response.status = errorIt.code;
+      expect(() => errorAxiosHandler(error)).toThrow(errorIt.type);
+    });
+  });
+
+  it('Throw HttpException error', () => {
+    error.response.status = 505;
+    expect(() => errorAxiosHandler(error)).toThrow(HttpException);
+  });
+
+  it('Axios error with no response, should throw Internal server error with msg unknown error', () => {
+    error.response = undefined;
+    expect(() => errorAxiosHandler(error)).toThrow(
+      InternalServerErrorException,
+    );
+  });
+});
diff --git a/api/src/common/utilities.ts b/api/src/common/utilities.ts
index c109df5..92d0457 100644
--- a/api/src/common/utilities.ts
+++ b/api/src/common/utilities.ts
@@ -10,12 +10,32 @@ import axios from 'axios';
 export const errorAxiosHandler = (e: any) => {
   if (!axios.isAxiosError(e)) throw new InternalServerErrorException(e);
 
-  if (e.response.status === 401) throw new UnauthorizedException();
-  if (e.response.status === 404) throw new NotFoundException();
-  if (e.response.status === 408) throw new RequestTimeoutException();
-  if (e.response.status === 500) throw new InternalServerErrorException();
-
-  if (e.response) throw new HttpException(e.response.data, e.response.status);
+  if (e.response) {
+    if (e.response.status === 401) throw new UnauthorizedException();
+    if (e.response.status === 404) throw new NotFoundException();
+    if (e.response.status === 408) throw new RequestTimeoutException();
+    if (e.response.status === 500) throw new InternalServerErrorException();
+    if (e.response.status && e.response.status)
+      throw new HttpException(e.response.data, e.response.status);
+  }
 
   throw new InternalServerErrorException('Unknown error');
 };
+
+/**
+ * Parse a string to a boolean
+ * @param {string} value - The value to parse.
+ * @param [defaultValue=false] - The default value to return if the value is not a valid boolean.
+ * @returns A boolean value.
+ */
+export const parseToBoolean = (
+  value: string,
+  defaultValue = false,
+): boolean => {
+  try {
+    if (value.toLowerCase() == 'true') return true;
+    return value.toLowerCase() == 'false' ? false : defaultValue;
+  } catch {
+    return defaultValue;
+  }
+};
diff --git a/api/src/engine/connectors/datashield/main.connector.ts b/api/src/engine/connectors/datashield/main.connector.ts
index 3c34f0f..454654e 100644
--- a/api/src/engine/connectors/datashield/main.connector.ts
+++ b/api/src/engine/connectors/datashield/main.connector.ts
@@ -4,7 +4,6 @@ import {
   InternalServerErrorException,
   Logger,
   NotImplementedException,
-  UnauthorizedException,
 } from '@nestjs/common';
 import { Request } from 'express';
 import { catchError, firstValueFrom } from 'rxjs';
@@ -102,7 +101,9 @@ export default class DataShieldService implements IEngineService {
       DataShieldService.logger.verbose(path);
       return {
         rawdata: {
-          data: 'Engine result are inconsitent',
+          data:
+            'Engine error when processing the request. Reason: ' +
+            response.data,
           type: MIME_TYPES.ERROR,
         },
       };
@@ -234,15 +235,13 @@ export default class DataShieldService implements IEngineService {
     return [transformToDomains.evaluate(response.data)];
   }
 
-  async getActiveUser(): Promise<User> {
-    const dummyUser = {
-      username: 'anonymous',
-      id: 'anonymousId',
-      fullname: 'anonymous',
-      email: 'anonymous@anonymous.com',
-      agreeNDA: true,
+  async getActiveUser(req: Request): Promise<User> {
+    const user = req.user as User;
+    return {
+      username: user.id,
+      id: user.id,
+      fullname: user.id,
     };
-    return dummyUser;
   }
 
   getAlgorithmsREST(): string {
diff --git a/api/src/engine/connectors/exareme/main.connector.ts b/api/src/engine/connectors/exareme/main.connector.ts
index daa996d..8d25f9f 100644
--- a/api/src/engine/connectors/exareme/main.connector.ts
+++ b/api/src/engine/connectors/exareme/main.connector.ts
@@ -54,7 +54,7 @@ export default class ExaremeService implements IEngineService {
   getConfiguration(): IConfiguration {
     return {
       contactLink: 'https://ebrains.eu/support/',
-      galaxy: true,
+      hasGalaxy: true,
     };
   }
 
diff --git a/api/src/engine/engine.constants.ts b/api/src/engine/engine.constants.ts
index e8fe577..3c9ae32 100644
--- a/api/src/engine/engine.constants.ts
+++ b/api/src/engine/engine.constants.ts
@@ -1,2 +1,3 @@
 export const ENGINE_MODULE_OPTIONS = 'EngineModuleOption';
 export const ENGINE_SERVICE = 'EngineService';
+export const ENGINE_SKIP_TOS = 'TOS_SKIP';
diff --git a/api/src/engine/engine.controller.ts b/api/src/engine/engine.controller.ts
index 8a704c0..f00a8e7 100644
--- a/api/src/engine/engine.controller.ts
+++ b/api/src/engine/engine.controller.ts
@@ -1,20 +1,10 @@
-import {
-  Controller,
-  Get,
-  Inject,
-  Post,
-  Req,
-  UseGuards,
-  UseInterceptors,
-} from '@nestjs/common';
+import { Controller, Get, Inject, Req, UseInterceptors } from '@nestjs/common';
 import { Request } from 'express';
 import { Observable } from 'rxjs';
-import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
 import { ENGINE_SERVICE } from './engine.constants';
 import { IEngineService } from './engine.interfaces';
 import { ErrorsInterceptor } from './interceptors/errors.interceptor';
 
-@UseGuards(JwtAuthGuard)
 @UseInterceptors(ErrorsInterceptor)
 @Controller()
 export class EngineController {
@@ -27,21 +17,6 @@ export class EngineController {
     return this.engineService.getAlgorithmsREST(request);
   }
 
-  @Get('activeUser')
-  async getActiveUser(@Req() request: Request) {
-    return await this.engineService.getActiveUser(request);
-  }
-
-  @Post('activeUser/agreeNDA')
-  async agreeNDA(@Req() request: Request) {
-    return await this.engineService.updateUser(request);
-  }
-
-  @Get('logout')
-  logout(@Req() request: Request): void {
-    this.engineService.logout(request);
-  }
-
   @Get('galaxy')
   galaxy(@Req() request: Request): Observable<string> | string {
     return this.engineService.getPassthrough?.('galaxy', request);
diff --git a/api/src/engine/engine.interfaces.ts b/api/src/engine/engine.interfaces.ts
index 7d745e4..b8b21e9 100644
--- a/api/src/engine/engine.interfaces.ts
+++ b/api/src/engine/engine.interfaces.ts
@@ -18,7 +18,7 @@ export interface IEngineOptions {
   baseurl: string;
 }
 
-export type IConfiguration = Pick<Configuration, 'contactLink' | 'galaxy'>;
+export type IConfiguration = Pick<Configuration, 'contactLink' | 'hasGalaxy'>;
 
 export interface IEngineService {
   //GraphQL
diff --git a/api/src/engine/engine.module.ts b/api/src/engine/engine.module.ts
index 35c4138..efdf729 100644
--- a/api/src/engine/engine.module.ts
+++ b/api/src/engine/engine.module.ts
@@ -1,8 +1,5 @@
 import { HttpModule, HttpService } from '@nestjs/axios';
 import { DynamicModule, Global, Logger, Module } from '@nestjs/common';
-import { REQUEST } from '@nestjs/core';
-import { Request } from 'express';
-import { IncomingMessage } from 'http';
 import { ENGINE_MODULE_OPTIONS, ENGINE_SERVICE } from './engine.constants';
 import { EngineController } from './engine.controller';
 import { IEngineOptions, IEngineService } from './engine.interfaces';
diff --git a/api/src/engine/engine.resolver.ts b/api/src/engine/engine.resolver.ts
index a6a845d..2ea02a1 100644
--- a/api/src/engine/engine.resolver.ts
+++ b/api/src/engine/engine.resolver.ts
@@ -1,10 +1,14 @@
-import { Inject, UseGuards } from '@nestjs/common';
+import { Inject, UseGuards, UseInterceptors } from '@nestjs/common';
 import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
 import { Request } from 'express';
 import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
 import { GQLRequest } from '../common/decorators/gql-request.decoractor';
 import { Md5 } from 'ts-md5';
-import { ENGINE_MODULE_OPTIONS, ENGINE_SERVICE } from './engine.constants';
+import {
+  ENGINE_MODULE_OPTIONS,
+  ENGINE_SERVICE,
+  ENGINE_SKIP_TOS,
+} from './engine.constants';
 import { IEngineOptions, IEngineService } from './engine.interfaces';
 import { Configuration } from './models/configuration.model';
 import { Domain } from './models/domain.model';
@@ -16,7 +20,13 @@ import {
 import { ExperimentCreateInput } from './models/experiment/input/experiment-create.input';
 import { ExperimentEditInput } from './models/experiment/input/experiment-edit.input';
 import { ListExperiments } from './models/experiment/list-experiments.model';
+import { ConfigService } from '@nestjs/config';
+import { parseToBoolean } from '../common/utilities';
+import { authConstants } from '../auth/auth-constants';
+import { Public } from 'src/auth/decorators/public.decorator';
+import { ErrorsInterceptor } from './interceptors/errors.interceptor';
 
+@UseInterceptors(ErrorsInterceptor)
 @UseGuards(JwtAuthGuard)
 @Resolver()
 export class EngineResolver {
@@ -24,14 +34,24 @@ export class EngineResolver {
     @Inject(ENGINE_SERVICE) private readonly engineService: IEngineService,
     @Inject(ENGINE_MODULE_OPTIONS)
     private readonly engineOptions: IEngineOptions,
+    private readonly configSerivce: ConfigService,
   ) {}
 
   @Query(() => Configuration)
+  @Public()
   configuration(): Configuration {
     const config = this.engineService.getConfiguration?.();
 
     const data = {
       ...(config ?? {}),
+      skipAuth: parseToBoolean(
+        this.configSerivce.get(authConstants.skipAuth),
+        true,
+      ),
+      skipTos: parseToBoolean(this.configSerivce.get(ENGINE_SKIP_TOS)),
+      enableSSO: parseToBoolean(
+        this.configSerivce.get(authConstants.enableSSO),
+      ),
       connectorId: this.engineOptions.type,
     };
 
diff --git a/api/src/engine/interceptors/errors.interceptor.ts b/api/src/engine/interceptors/errors.interceptor.ts
index 47e61fc..17bd220 100644
--- a/api/src/engine/interceptors/errors.interceptor.ts
+++ b/api/src/engine/interceptors/errors.interceptor.ts
@@ -30,7 +30,9 @@ export class ErrorsInterceptor implements NestInterceptor {
 
         this.logger.log(e.message);
         this.logger.verbose(
-          `[Error ${e.response.status}] ${e.response.data.message}`,
+          `[Error ${e.response.status}] ${
+            e.response.data.message ?? e.response.data
+          }`,
         );
         throw new HttpException(e.response.data, e.response.status); // catch errors, maybe make it optional (module parameter)
       }),
diff --git a/api/src/engine/models/configuration.model.ts b/api/src/engine/models/configuration.model.ts
index 69edf36..d2d390d 100644
--- a/api/src/engine/models/configuration.model.ts
+++ b/api/src/engine/models/configuration.model.ts
@@ -5,11 +5,20 @@ export class Configuration {
   connectorId: string;
 
   @Field({ nullable: true, defaultValue: false })
-  galaxy?: boolean;
+  hasGalaxy?: boolean;
 
   @Field({ nullable: true })
   contactLink?: string;
 
   @Field()
   version: string;
+
+  @Field({ nullable: true })
+  skipAuth?: boolean;
+
+  @Field({ nullable: true, defaultValue: false })
+  skipTos?: boolean;
+
+  @Field({ nullable: true, defaultValue: true })
+  enableSSO?: boolean;
 }
diff --git a/api/src/engine/models/result/table-result.model.ts b/api/src/engine/models/result/table-result.model.ts
index 664d64c..a733683 100644
--- a/api/src/engine/models/result/table-result.model.ts
+++ b/api/src/engine/models/result/table-result.model.ts
@@ -22,6 +22,6 @@ export class TableResult extends Result {
   @Field(() => [Header])
   headers: Header[];
 
-  @Field(() => ThemeType, { defaultValue: ThemeType.DEFAULT })
+  @Field(() => ThemeType, { defaultValue: ThemeType.DEFAULT, nullable: true })
   theme?: ThemeType;
 }
diff --git a/api/src/main/app.module.ts b/api/src/main/app.module.ts
index 9ec49e6..1555caa 100644
--- a/api/src/main/app.module.ts
+++ b/api/src/main/app.module.ts
@@ -3,6 +3,7 @@ import { Module } from '@nestjs/common';
 import { ConfigModule } from '@nestjs/config';
 import { GraphQLModule } from '@nestjs/graphql';
 import { TypeOrmModule } from '@nestjs/typeorm';
+import { GraphQLError } from 'graphql';
 import { join } from 'path';
 import { AuthModule } from 'src/auth/auth.module';
 import { EngineModule } from 'src/engine/engine.module';
@@ -25,6 +26,19 @@ import { AppService } from './app.service';
         credentials: true,
         origin: [/http:\/\/localhost($|:\d*)/, /http:\/\/127.0.0.1($|:\d*)/],
       },
+      formatError: (error: GraphQLError) => {
+        const extensions = {
+          code: error.extensions.code,
+          status:
+            error.extensions?.response?.statusCode ??
+            error.extensions.exception.status,
+          message:
+            error.extensions?.response?.message ??
+            error.extensions?.exception?.message,
+        };
+
+        return { ...error, extensions: { ...error.extensions, ...extensions } };
+      },
     }),
     EngineModule.forRoot({
       type: process.env.ENGINE_TYPE,
diff --git a/api/src/schema.gql b/api/src/schema.gql
index 5abb541..4d248dc 100644
--- a/api/src/schema.gql
+++ b/api/src/schema.gql
@@ -16,9 +16,12 @@ type AuthenticationOutput {
 
 type Configuration {
   connectorId: String!
-  galaxy: Boolean
+  hasGalaxy: Boolean
   contactLink: String
   version: String!
+  skipAuth: Boolean
+  skipTos: Boolean
+  enableSSO: Boolean
 }
 
 type Dataset {
@@ -94,7 +97,7 @@ type TableResult {
   name: String!
   data: [[String!]!]!
   headers: [Header!]!
-  theme: ThemeType!
+  theme: ThemeType
 }
 
 enum ThemeType {
diff --git a/api/src/users/users.resolver.spec.ts b/api/src/users/users.resolver.spec.ts
index 6ea7e0f..e449f71 100644
--- a/api/src/users/users.resolver.spec.ts
+++ b/api/src/users/users.resolver.spec.ts
@@ -102,6 +102,10 @@ describe('UsersResolver', () => {
     });
   });
 
+  it('Undefined user should not throw exception', async () => {
+    expect(await resolver.getUser(req, undefined)).toBeTruthy();
+  });
+
   it('Update user from engine ', async () => {
     expect(await resolver.updateUser(req, updateData, user)).toStrictEqual({
       ...user,
@@ -116,4 +120,8 @@ describe('UsersResolver', () => {
       ...internUser,
     });
   });
+
+  it('Undefined user should not throw exception', async () => {
+    expect(await resolver.updateUser(req, updateData, user)).toBeTruthy();
+  });
 });
diff --git a/api/src/users/users.resolver.ts b/api/src/users/users.resolver.ts
index 46c77cc..13ec63a 100644
--- a/api/src/users/users.resolver.ts
+++ b/api/src/users/users.resolver.ts
@@ -43,7 +43,9 @@ export class UsersResolver {
 
     // Checking if the user exists in the internal database. If it does, it will assign the user to the `user` object.
     try {
-      const internalUser = await this.usersService.findOne(reqUser.id);
+      const internalUser = reqUser
+        ? await this.usersService.findOne(reqUser.id)
+        : undefined;
 
       if (internalUser && (!user.id || internalUser.id === user.id)) {
         Object.assign(user, internalUser);
@@ -71,10 +73,10 @@ export class UsersResolver {
   async updateUser(
     @GQLRequest() request: Request,
     @Args('updateUserInput') updateUserInput: UpdateUserInput,
-    @CurrentUser() user: User,
+    @CurrentUser() user?: User,
   ) {
     if (this.engineService.updateUser)
-      return this.engineService.updateUser(request, user.id, updateUserInput);
+      return this.engineService.updateUser(request, user?.id, updateUserInput);
 
     await this.usersService.update(user.id, updateUserInput);
 
-- 
GitLab