diff --git a/docker-compose.yml b/docker-compose.yml
index 11e32ebff4d0c482e9d91d16869909c433877e47..853ea1f21da9f562ec37c645e04f3237c2be7870 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,7 +13,8 @@ services:
       - OIDC_CLIENT_ID=${DEV_OIDC_CLIENT_ID}
       - OIDC_CLIENT_SECRET=${DEV_OIDC_CLIENT_SECRET}
       - GLC_CLIENT_ID=${DEV_GLC_CLIENT_ID}
-      - GLC_CLIENT_SECRET=${DEV_GLC_CLIENT_SECRET}
+      - GLC_CLIENT_SECRET=${DEV_GLC_CLIENT_SECRET}  
+    restart: unless-stopped 
     depends_on:
       - redis
         
@@ -26,6 +27,7 @@ services:
       - ${REDIS_PORT}:6379
     volumes:
       - redis-data:/data
+    restart: unless-stopped 
 
 volumes:
   redis-data:
diff --git a/src/authentication/authentication.controller.ts b/src/authentication/authentication.controller.ts
index f3e8020e34a67bcc96038bf6e6649e407461695c..0d9610ba69a81d2a60e0d0d89c92eeac8b01e1fd 100644
--- a/src/authentication/authentication.controller.ts
+++ b/src/authentication/authentication.controller.ts
@@ -1,320 +1,54 @@
-import { Controller, Get, Res, Req, Param, Query, Logger } from '@nestjs/common';
-import { ConfigService } from '../configuration/config.service';
-import * as request from 'request';
-import * as jwt from 'jsonwebtoken';
-import { ApiResponse } from '@nestjs/swagger';
-import * as redis from 'redis';
-import * as uuid4 from 'uuid/v4';
+import { Controller, Get, Res, Param, Query } from '@nestjs/common';
+import { ApiResponse, ApiUseTags } from '@nestjs/swagger';
 
+
+import { AuthenticationService } from './authentication.service';
+
+@ApiUseTags('authentication')
 @Controller()
 export class AuthenticationController {
-  conf: any = {};
   constructor(
-    private configService: ConfigService,
-  ) {
-    this.conf = this.configService.config;
-    this.discoverIdentityProvider('OIDC');
-    this.discoverIdentityProvider('GLC');
-  }
+    private _authService: AuthenticationService,
+  ) {}
 
   @Get('/login/:identityProvider')
   @ApiResponse({ status: 302, description: 'Redirection to the appropriate url allowing the user to connect to the identity provider.' })
   @ApiResponse({ status: 500, description: 'Occurs when the service couldn\'t get the identity provider configuration from the discovery endpoint.' })
-  login(@Req() req, @Res() res) {
-    const idp = req.params.identityProvider.toUpperCase();
-    if (this.conf && this.conf.providers[idp]) {
-      const idpConf = this.conf.providers[idp];
-      Logger.log('[-] Login');
-
-      const uuid = uuid4();
-
-      this.setRedisKeyValue(uuid, idp);
-
-      let url = `${idpConf.discoveryResult.authorization_endpoint}?scope=${idpConf.scopes}`;
-      url += `&response_type=${idpConf.response_type}&client_id=${idpConf.client_id}`;
-      url += `&redirect_uri=${this.conf.redirect_uri}&state=${uuid}`;
-
-      const encodedUrl = encodeURI(url);
-
-      Logger.log('    [*] Encoded url:', encodedUrl);
-
-      res.redirect(302, encodedUrl);
-    } else {
-      Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', idp);
-      res.status(400).send({ message: 'Failed to get the configuration of the identity provider.' });
-    }
+  login(@Param('identityProvider') identityProvider: string, @Res() res) {
+    const idp = identityProvider.toUpperCase(); // By convention the provider is always uppecased in config and in var env
+    this._authService.login(idp, (err, encodedUrl) => {
+      if (err !== null) {
+        res.status(err.status).send({ message: err.message });
+      } else {
+        res.redirect(302, encodedUrl);
+      }
+    });
   }
 
   @Get('/token')
   @ApiResponse({ status: 200, description: 'JWT generated' })
-  @ApiResponse({ status: 400, description: 'The request failed for the reason indicated in the body of repsonse.' })
-  getOidcToken(@Res() res, @Query('code') code: string, @Query('state') state: string) {
-    Logger.log('[-] Token Endpoint');
-    Logger.log('   [*] code: ', code);
-    Logger.log('   [*] state: ', state);
-
-    this.getRedisValueByKey(state, (idp) => {
-      if (idp !== null) {
-        Logger.log('    [*] The state received in parameter is associated to the following identity provider: ', idp);
-        if (this.conf && this.conf.providers[idp]) {
-          const idpConf = this.conf.providers[idp];
-
-          const payload = {
-            grant_type: idpConf.grant_type,
-            code,
-            redirect_uri: this.conf.redirect_uri,
-          };
-
-          Logger.log('    [*] payload sent: ', JSON.stringify(payload));
-          Logger.log('[-] Token Request');
-
-          request.post(idpConf.discoveryResult.token_endpoint, { form: payload }, (error: any, response: any, body: any) => {
-
-            Logger.log('    [*] Response Status Code:', response.statusCode);
-            Logger.log('    [*] Response body:', body);
-
-            if (error || !body || response.statusCode !== 200) {
-              Logger.error('    [x] error:', error);
-              res.status(400).send(error);
-            } else {
-              if (body) {
-                body = JSON.parse(body);
-                const userInfoOptions = {
-                  idp,
-                  idp_conf: idpConf,
-                  access_token: body.access_token,
-                  id_token: body.id_token,
-                };
-                this.getUserInfo(userInfoOptions, (getUserInfoErr: string, userInfo: any) => {
-                  if (getUserInfoErr) {
-                    res.status(400).send(getUserInfoErr);
-                  } else {
-                    this.createOrUpdateKongUser(userInfo.email, (createOrUpdateErr: string, email: string) => {
-                      if (createOrUpdateErr) {
-                        res.status(400).send(createOrUpdateErr);
-                      } else {
-                        this.getUserJWTCredential(email, (getUserJWTCredErr: string, cred: any) => {
-                          if (getUserJWTCredErr) {
-                            res.status(400).send(getUserJWTCredErr);
-                          } else {
-                            userInfo.iss = cred.key;
-                            userInfo.secret = cred.secret;
-                            const jwtToken = this.generateJWT(userInfo);
-                            res.status(200).json({ token: jwtToken });
-                          }
-                        });
-                      }
-                    });
-                  }
-                });
-              }
-            }
-          }).auth(idpConf.client_id, idpConf.client_secret, true);
-        } else {
-          Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', idp);
-          res.status(400).send({ message: 'Failed to get the configuration of the identity provider.' });
-        }
+  @ApiResponse({ status: 400, description: 'The request failed for the reason indicated in the body of response.' })
+  @ApiResponse({ status: 500, description: 'The connection to redis server failed.' })
+  getTokens(@Res() res, @Query('code') code: string, @Query('state') state: string) {
+    this._authService.getToken(code, state, (err, token) => {
+      if (err !== null) {
+        res.status(err.status).send({ message: err.message });
       } else {
-        Logger.error('    [x] Error: The state received in paramter is not associated to any identity provider. State:', state);
-        res.status(400).send({ message: 'The state received in paramter is not associated to any identity provider.' });
+        res.status(200).json(token);
       }
     });
   }
 
   @Get('/logout')
   @ApiResponse({ status: 302, description: 'Redirection to the appropriate url allowing the user to logout from the app.' })
+  @ApiResponse({ status: 500, description: 'Failed to get the configuration of the identity provider.' })
   logout(@Res() res, @Query('id_token') id_token: string, @Query('identity_provider') identity_provider: string) {
-    Logger.log(`[x] logout from: ${identity_provider}`);
-
-    if (this.conf && this.conf.providers[identity_provider]) {
-      const idpConf = this.conf.providers[identity_provider];
-
-      let url = `${idpConf.discoveryResult.end_session_endpoint}?post_logout_redirect_uri=${this.conf.post_logout_redirect_uri}`;
-      url += `&id_token_hint=${id_token}`;
-      const encodedUrl = encodeURI(url);
-
-      Logger.log(encodedUrl);
-
-      res.redirect(302, encodedUrl);
-    } else {
-      Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', identity_provider);
-      res.status(400).send({ message: 'Failed to get the configuration of the identity provider.' });
-    }
-  }
-
-  getUserInfo(opts: { idp: string, idp_conf: any, access_token: string, id_token: string }, done: any) {
-    const userInfoOpts = {
-      url: opts.idp_conf.discoveryResult.userinfo_endpoint,
-      headers: {
-        Authorization: `Bearer ${opts.access_token}`,
-      },
-    };
-
-    Logger.log('[-] UserInfo Request');
-
-    request.get(userInfoOpts, (err: any, response: any, content: any) => {
-
-      Logger.log('    [*] Response Status Code:', response.statusCode);
-      Logger.log('    [*] Response body:', content);
-
-      if (err || !content || response.statusCode !== 200) {
-        Logger.error('    [x] Error:', err);
-        done('User info request failed.');
+    this._authService.logout(id_token, identity_provider, (err, encodedUrl) => {
+      if (err !== null) {
+        res.status(err.status).send({ message: err.message });
       } else {
-        content = JSON.parse(content);
-
-        content.identity_provider = opts.idp;
-        content.id_token = opts.id_token;
-
-        done(null, content);
+        res.redirect(302, encodedUrl);
       }
     });
   }
-
-  createOrUpdateKongUser(email: string, done: any) {
-
-    Logger.log('[-] Generating Kong User with user name: ', email);
-
-    request.put(`${this.conf.kongConsumers}/${email}`, { form: { username: email } }, (err: any, response: any, content: any) => {
-      Logger.log('    [*] Response Status Code:', response.statusCode);
-      Logger.log('    [*] Response body:', content);
-
-      if (err || !content || response.statusCode !== 200) {
-        Logger.error(' [x] Error creating consumer in kong: ', err);
-        done('Failed to generate Kong User.');
-      } else {
-        done(null, email);
-      }
-    });
-  }
-
-  getUserJWTCredential(email: string, done: any) {
-
-    Logger.log('[-] Getting JWT credentials for user: ', email);
-
-    request.get(`${this.conf.kongConsumers}/${email}/jwt`, (err: any, response: any, content: any) => {
-
-      Logger.log('    [*] Response Status Code:', response.statusCode);
-      Logger.log('    [*] Response body:', content);
-
-      let res = null;
-      if (err || !content || response.statusCode !== 200) {
-        Logger.error(' [x] Error getting consumer JWT creadentials: ', err);
-        done('Failed to get JWT credentials.');
-      } else {
-        content = JSON.parse(content);
-        if (content.total > 0) {
-          res = content.data[0];
-        }
-
-        if (res === null) {
-          this.generateUserJWTCredential(email, (generateUserJWTCredentialErr: string, cred: any) => {
-            done(generateUserJWTCredentialErr, cred);
-          });
-        } else {
-          done(null, res);
-        }
-      }
-    });
-  }
-
-  generateUserJWTCredential(email: string, done: any) {
-
-    Logger.log('[-] Generating JWT credentials for user: ', email);
-
-    request.post(`${this.conf.kongConsumers}/${email}/jwt`, (err: any, response: any, content: any) => {
-
-      Logger.log('    [*] Response Status Code:', response.statusCode);
-      Logger.log('    [*] Response body:', content);
-
-      if (err || !content || response.statusCode !== 200) {
-        Logger.error(' [x] Error creating consumer JWT creadentials: ', err);
-        done('Failed to generate JWT Credentials for the user');
-      } else {
-        content = JSON.parse(content);
-
-        done(null, content);
-      }
-    });
-  }
-
-  generateJWT(info: any) {
-
-    Logger.log('[-] Generating JWT');
-
-    const jwtBearerToken: any = jwt.sign(
-      {
-        id: info.sub,
-        firstname: info.given_name,
-        lastname: info.family_name,
-        identity_provider: info.identity_provider,
-        email: info.email,
-        iss: info.iss,
-        id_token: info.id_token,
-        exp: Math.floor(Date.now() / 1000) + (60 * 60),
-      },
-      // { key: RSA_PRIVATE_KEY, passphrase: "metropoledelyonportaildata2018" },
-      info.secret,
-      {
-        algorithm: 'HS256',
-        // algorithm: 'RS256',
-      },
-    );
-
-    return jwtBearerToken;
-  }
-
-  discoverIdentityProvider(identityProvider: string) {
-    request.get(this.conf.providers[identityProvider].discoveryUrl, (err: any, response: any, content: any) => {
-      Logger.log('[-] Discovering configuration for identity Provider:', identityProvider);
-      Logger.log('    [*] Response Status Code:', response.statusCode);
-      Logger.log('    [*] Response body:', content);
-
-      if (err || !content || response.statusCode !== 200) {
-        Logger.error(' [x] Error discovering the configuration for oidc provider: ', err);
-      } else {
-        content = JSON.parse(content);
-        this.conf.providers[identityProvider].discoveryResult = content;
-      }
-    });
-  }
-
-  connectToRedis(done) {
-    Logger.log(`[-] Connecting to redis`);
-
-    const client = redis.createClient({ host: this.conf.redis.host, port: this.conf.redis.port });
-
-    client.on('error', (err) => {
-      Logger.error('    [x] Error on redis client: ' + err);
-    });
-
-    done(client);
-  }
-
-  setRedisKeyValue(key: string, value: string) {
-    Logger.log(`[-] setRedisKeyValue with params: ${key} ${value}`);
-    this.connectToRedis((client) => {
-
-      Logger.log('    [*] Redis client connected.');
-
-      client.set(key, value, 'EX', this.conf.redis.ttl, (err, res) => {
-        Logger.log(`    [*] Setting key/pair result => ${err} ${res}`);
-        client.quit();
-      });
-    });
-  }
-
-  getRedisValueByKey(key: string, done) {
-    Logger.log(`[-] getRedisValueByKey with key: ${key}`);
-    this.connectToRedis((client) => {
-
-      Logger.log('    [*] Redis client connected.');
-
-      client.get(key, (err, res) => {
-        Logger.log(`    [*] Get by key => ${err} ${res}`);
-        client.quit();
-        done(res);
-      });
-    });
-  }
 }
diff --git a/src/authentication/authentication.module.ts b/src/authentication/authentication.module.ts
index 62e91beee410b5e205c5f34500214aee63fd92c2..afa9d1214836de20896a5c52621335d8516c81d0 100644
--- a/src/authentication/authentication.module.ts
+++ b/src/authentication/authentication.module.ts
@@ -1,7 +1,9 @@
 import { Module } from '@nestjs/common';
 import { AuthenticationController } from './authentication.controller';
+import { AuthenticationService } from './authentication.service';
 
 @Module({
   controllers: [AuthenticationController],
+  providers: [AuthenticationService],
 })
 export class AuthenticationModule {}
diff --git a/src/authentication/authentication.service.spec.ts b/src/authentication/authentication.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d6cefa6e670e25c21caae43841fcbeb02517c7eb
--- /dev/null
+++ b/src/authentication/authentication.service.spec.ts
@@ -0,0 +1,15 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AuthenticationService } from './authentication.service';
+
+describe('AuthenticationService', () => {
+  let service: AuthenticationService;
+  beforeAll(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      providers: [AuthenticationService],
+    }).compile();
+    service = module.get<AuthenticationService>(AuthenticationService);
+  });
+  it('should be defined', () => {
+    expect(service).toBeDefined();
+  });
+});
diff --git a/src/authentication/authentication.service.ts b/src/authentication/authentication.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aac465cec9a7ca5879e43f85714152e197f1d4cf
--- /dev/null
+++ b/src/authentication/authentication.service.ts
@@ -0,0 +1,345 @@
+import { Injectable, Logger } from '@nestjs/common';
+import { ConfigService } from 'configuration/config.service';
+import * as request from 'request';
+import * as uuid4 from 'uuid/v4';
+import * as redis from 'redis';
+import * as jwt from 'jsonwebtoken';
+
+@Injectable()
+export class AuthenticationService {
+  conf: any = {};
+  constructor(
+    private configService: ConfigService,
+  ) {
+    this.conf = this.configService.config;
+    for (const provider in this.conf.providers) {
+      // Discover the conf for each providers
+      if (this.conf.providers.hasOwnProperty(provider)) {
+        this.discoverIdentityProvider(provider);
+      }
+    }
+  }
+
+  private discoverIdentityProvider(identityProvider: string) {
+    // Call the discovery endpoint of the identity provider
+    request.get(this.conf.providers[identityProvider].discoveryUrl, (err: any, response: any, content: any) => {
+      Logger.log('[-] Discovering configuration for identity Provider:', identityProvider);
+      if (response) Logger.log('    [*] Response Status Code:', response.statusCode);
+      if (content) Logger.log('    [*] Response body:', content);
+
+      if (err || !content || response.statusCode !== 200) {
+        Logger.error(` [x] Error discovering the configuration for provider: ${identityProvider}. Error was:`, JSON.stringify(err));
+      } else {
+        content = JSON.parse(content);
+        // Set the discovered conf in the controller conf object
+        this.conf.providers[identityProvider].discoveryResult = content;
+      }
+    });
+  }
+
+  login(idp: string, done) {
+    if (this.conf && this.conf.providers[idp] && this.conf.providers[idp].discoveryResult) {
+      const idpConf = this.conf.providers[idp];
+      Logger.log('[-] Login');
+
+      // Generate a random uuid that will be the state in the connexion echange (see OIDC spec )
+      const state = uuid4();
+      // Push a state/provider key pair in redis
+      this.setRedisKeyValue(state, idp);
+
+      // Generate the url base on the provider conf
+      let url = `${idpConf.discoveryResult.authorization_endpoint}?scope=${idpConf.scopes}`;
+      url += `&response_type=${idpConf.response_type}&client_id=${idpConf.client_id}`;
+      url += `&redirect_uri=${this.conf.redirect_uri}&state=${state}`;
+
+      const encodedUrl = encodeURI(url);
+
+      Logger.log('    [*] Encoded url:', encodedUrl);
+
+      done(null, encodedUrl);
+    } else {
+      Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', idp);
+      done({status: 500, message: 'Failed to get the configuration of the identity provider.'});
+    }
+  }
+
+  getToken(code: string, state: string, done) {
+    Logger.log('[-] GetTokens Method');
+    Logger.log('   [*] code: ', code);
+    Logger.log('   [*] state: ', state);
+
+    // Get the state/provider key pair from redis
+    this.getRedisValueByKey(state, (err, idp) => {
+      // It can be null if the state has been modified (not generated by the login endpoint) or if it has expired
+      if (err !== null) {
+        done({status: 500, message: 'One of the required services wasn\'t available, please retry later.'});
+      } else {
+        if (idp !== null) {
+          Logger.log('    [*] The state received in parameter is associated to the following identity provider: ', idp);
+          if (this.conf && this.conf.providers[idp]) {
+            // Get the conf of the provider associated with the state
+            const idpConf = this.conf.providers[idp];
+
+            const payload = {
+              grant_type: idpConf.grant_type,
+              code,
+              redirect_uri: this.conf.redirect_uri,
+            };
+
+            Logger.log('    [*] payload sent: ', JSON.stringify(payload));
+            Logger.log('[-] Token Request');
+
+            // Exchange the code against an id_token and an access_token
+            request.post(idpConf.discoveryResult.token_endpoint, { form: payload }, (error: any, response: any, body: any) => {
+
+              Logger.log('    [*] Response Status Code:', response.statusCode);
+              Logger.log('    [*] Response body:', body);
+
+              if (error || !body || response.statusCode !== 200) {
+                Logger.error('    [x] error:', error);
+                done({status: 400, message: 'Failed to echange the code against tokens.'});
+              } else {
+                if (body) {
+                  body = JSON.parse(body);
+                  const userInfoOptions = {
+                    idp,
+                    idp_conf: idpConf,
+                    access_token: body.access_token,
+                    id_token: body.id_token,
+                  };
+                  // Retrieve the user info with the tokens received
+                  this.getUserInfo(userInfoOptions, (getUserInfoErr: string, userInfo: any) => {
+                    if (getUserInfoErr) {
+                      done({status: 400, message: getUserInfoErr});
+                    } else {
+                      // Create or update the kong user based on the user info received
+                      this.createOrUpdateKongUser(userInfo.email, (createOrUpdateErr: string, email: string) => {
+                        if (createOrUpdateErr) {
+                          done({status: 400, message: createOrUpdateErr});
+                        } else {
+                          // Get user jwt credentials from kong in order to sign our own Json Web Token
+                          this.getUserJWTCredential(email, (getUserJWTCredErr: string, cred: any) => {
+                            if (getUserJWTCredErr) {
+                              done({status: 400, message: getUserJWTCredErr});
+                            } else {
+                              userInfo.iss = cred.key;
+                              userInfo.secret = cred.secret;
+                              const jwtToken = this.generateJWT(userInfo);
+                              done(null, jwtToken);
+                            }
+                          });
+                        }
+                      });
+                    }
+                  });
+                }
+              }
+            }).auth(idpConf.client_id, idpConf.client_secret, true);
+          } else {
+            Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', idp);
+            done({status: 400, message: 'Failed to get the configuration of the identity provider.'});
+          }
+        } else {
+          Logger.error('    [x] Error: The state received in parameter is not associated to any identity provider. State:', state);
+          done({status: 400, message: 'The state received in parameter is not associated to any identity provider.'});
+        }
+      }
+    });
+  }
+
+  logout(id_token: string, identity_provider, done) {
+    Logger.log(`[x] logout from: ${identity_provider}`);
+
+    if (this.conf && this.conf.providers[identity_provider]) {
+      // Get the identy provider conf
+      const idpConf = this.conf.providers[identity_provider];
+
+      // Generate the url with the identity provider conf
+      let url = `${idpConf.discoveryResult.end_session_endpoint}?post_logout_redirect_uri=${this.conf.post_logout_redirect_uri}`;
+      url += `&id_token_hint=${id_token}`;
+      const encodedUrl = encodeURI(url);
+
+      Logger.log(`Logout url: ${encodedUrl}`);
+
+      done(null, encodedUrl);
+    } else {
+      Logger.error('    [x] Error: Failed to get the configuration of the identity provider: ', identity_provider);
+      done({status: 500, message: 'Failed to get the configuration of the identity provider.'});
+    }
+  }
+
+  private setRedisKeyValue(key: string, value: string) {
+    Logger.log(`[-] setRedisKeyValue with params: ${key} ${value}`);
+    this.connectToRedis((client) => {
+      if (client !== null) {
+        Logger.log('    [*] Redis client connected.');
+
+        // Set key value with expiration time in seconds
+        client.set(key, value, 'EX', this.conf.redis.ttl, (err, res) => {
+          Logger.log(`    [*] Setting key/pair result => ${err} ${res}`);
+          client.quit();
+        });
+      } else {
+        Logger.error('    [x] Couldn\'t set redis key/value');
+      }
+    });
+  }
+
+  private getRedisValueByKey(key: string, done) {
+    Logger.log(`[-] getRedisValueByKey with key: ${key}`);
+    this.connectToRedis((client) => {
+      if (client !== null) {
+        Logger.log('    [*] Redis client connected.');
+
+        client.get(key, (err, res) => {
+          Logger.log(`    [*] Get by key => ${err} ${res}`);
+          client.quit();
+          done(null, res);
+        });
+      } else {
+        Logger.error('    [x] Couldn\'t get redis value with the key provided.');
+        done('Failed to connect to redis server.');
+      }
+    });
+  }
+
+  private connectToRedis(done) {
+    Logger.log(`[-] Connecting to redis`);
+
+    const client = redis.createClient({ host: this.conf.redis.host, port: this.conf.redis.port });
+
+    client.on('error', (err) => {
+      Logger.error('    [x] Error on redis client: ' + err);
+      client.quit();
+      done(null);
+    });
+
+    client.on('ready', (ready) => {
+      Logger.log('    [*] Client connected: ' + ready);
+      done(client);
+    });
+  }
+
+  private getUserInfo(opts: { idp: string, idp_conf: any, access_token: string, id_token: string }, done: any) {
+    const userInfoOpts = {
+      url: opts.idp_conf.discoveryResult.userinfo_endpoint,
+      headers: {
+        Authorization: `Bearer ${opts.access_token}`,
+      },
+    };
+
+    Logger.log('[-] UserInfo Request');
+
+    request.get(userInfoOpts, (err: any, response: any, content: any) => {
+
+      Logger.log('    [*] Response Status Code:', response.statusCode);
+      Logger.log('    [*] Response body:', content);
+
+      if (err || !content || response.statusCode !== 200) {
+        Logger.error('    [x] Error:', err);
+        done('User info request failed.');
+      } else {
+        content = JSON.parse(content);
+
+        content.identity_provider = opts.idp;
+        content.id_token = opts.id_token;
+
+        done(null, content);
+      }
+    });
+  }
+
+  private createOrUpdateKongUser(email: string, done: any) {
+    Logger.log('[-] Generating Kong User with user name: ', email);
+
+    request.put(`${this.conf.kongConsumers}/${email}`, { form: { username: email } }, (err: any, response: any, content: any) => {
+      Logger.log('    [*] Response Status Code:', response.statusCode);
+      Logger.log('    [*] Response body:', content);
+
+      if (err || !content || response.statusCode !== 200) {
+        Logger.error(' [x] Error creating consumer in kong: ', err);
+        done('Failed to generate Kong User.');
+      } else {
+        done(null, email);
+      }
+    });
+  }
+
+  private getUserJWTCredential(email: string, done: any) {
+
+    Logger.log('[-] Getting JWT credentials for user: ', email);
+
+    request.get(`${this.conf.kongConsumers}/${email}/jwt`, (err: any, response: any, content: any) => {
+
+      Logger.log('    [*] Response Status Code:', response.statusCode);
+      Logger.log('    [*] Response body:', content);
+
+      let res = null;
+      if (err || !content || response.statusCode !== 200) {
+        Logger.error(' [x] Error getting consumer JWT creadentials: ', err);
+        done('Failed to get JWT credentials.');
+      } else {
+        content = JSON.parse(content);
+        // If at least ine creadential exist, use the first one
+        if (content.total > 0) {
+          res = content.data[0];
+        }
+
+        // If no credentials exist for the user generate one
+        if (res === null) {
+          this.generateUserJWTCredential(email, (generateUserJWTCredentialErr: string, cred: any) => {
+            done(generateUserJWTCredentialErr, cred);
+          });
+        } else {
+          done(null, res);
+        }
+      }
+    });
+  }
+
+  private generateUserJWTCredential(email: string, done: any) {
+
+    Logger.log('[-] Generating JWT credentials for user: ', email);
+
+    request.post(`${this.conf.kongConsumers}/${email}/jwt`, (err: any, response: any, content: any) => {
+
+      Logger.log('    [*] Response Status Code:', response.statusCode);
+      Logger.log('    [*] Response body:', content);
+
+      if (err || !content || response.statusCode !== 200) {
+        Logger.error(' [x] Error creating consumer JWT creadentials: ', err);
+        done('Failed to generate JWT Credentials for the user');
+      } else {
+        content = JSON.parse(content);
+
+        done(null, content);
+      }
+    });
+  }
+
+  private generateJWT(info: any) {
+
+    Logger.log('[-] Generating JWT');
+
+    const jwtBearerToken: any = jwt.sign(
+      {
+        id: info.sub,
+        firstname: info.given_name,
+        lastname: info.family_name,
+        identity_provider: info.identity_provider,
+        email: info.email,
+        iss: info.iss,
+        id_token: info.id_token,
+        exp: Math.floor(Date.now() / 1000) + (60 * 60),
+      },
+      // { key: RSA_PRIVATE_KEY, passphrase: "metropoledelyonportaildata2018" },
+      info.secret,
+      {
+        algorithm: 'HS256',
+        // algorithm: 'RS256',
+      },
+    );
+
+    return jwtBearerToken;
+  }
+}
diff --git a/src/main.ts b/src/main.ts
index 2d76242d97680e95b669f31e4b91a1c2226df245..50fa433b91044bcae2a940f6ac0d651d570b094d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -11,6 +11,7 @@ async function bootstrap() {
     .setTitle('Authentication service API')
     .setDescription('This service expose the endpoints needed in order to Login/Logout with the OIDC/Grand Lyon Connect')
     .setVersion('0.1')
+    .addTag('authentication')
     .build();
   const document = SwaggerModule.createDocument(app, options);