diff --git a/build.gradle b/build.gradle
index b0f93a8b25f6963e6821448de89bd40a1cb6ccc0..508d65aa095ac10dfd5fe282e30b242f8b5820a8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ plugins {
 	id "org.sonarqube" version "3.2.0"
 }
 
-version = '1.6.5'
+version = '1.7.0'
 
 task buildGUI(type: Exec) {
 	println 'Building using Angular CLI'
diff --git a/package-lock.json b/package-lock.json
index 2158b8b4014ac3f0dbe34ebdc01a4c2d4d563d8d..881b777c79885b41a9fc397b3d9c20efa1751599 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "nmaas-portal",
-  "version": "1.6.5",
+  "version": "1.7.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "nmaas-portal",
-      "version": "1.6.5",
+      "version": "1.7.0",
       "license": "Apache 2.0",
       "dependencies": {
         "@angular/animations": "17.3.12",
@@ -35,7 +35,7 @@
         "jquery": "^3.6.0",
         "lodash": "^4.17.21",
         "ng-event-source": "^1.0.14",
-        "ng-recaptcha": "^13.0.0",
+        "ng-recaptcha": "^13.2.1",
         "ng-terminal": "^6.3.0",
         "ngx-pagination": "^6.0.3",
         "ngx-webstorage-service": "^5.0.0",
diff --git a/package.json b/package.json
index 09a8e774d77de12a925911a29ee16690f7e7194c..9402af9537167709179f216f116de9a9ef4cbefa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nmaas-portal",
-  "version": "1.6.5",
+  "version": "1.7.0",
   "license": "Apache 2.0",
   "angular-cli": {},
   "scripts": {
@@ -40,7 +40,7 @@
     "jquery": "^3.6.0",
     "lodash": "^4.17.21",
     "ng-event-source": "^1.0.14",
-    "ng-recaptcha": "^13.0.0",
+    "ng-recaptcha": "^13.2.1",
     "ng-terminal": "^6.3.0",
     "ngx-pagination": "^6.0.3",
     "ngx-webstorage-service": "^5.0.0",
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts
index 28a607296fcb770e6d847693cc44b139be7170cb..c9f6f599a90484886cf179ce005644d846eec145 100644
--- a/src/app/app.component.spec.ts
+++ b/src/app/app.component.spec.ts
@@ -1,12 +1,10 @@
 /* tslint:disable:no-unused-variable */
 
-import { TestBed, waitForAsync } from '@angular/core/testing';
-import { AppComponent } from './app.component';
-import { RouterTestingModule} from '@angular/router/testing';
+import {TestBed, waitForAsync} from '@angular/core/testing';
+import {AppComponent} from './app.component';
+import {RouterTestingModule} from '@angular/router/testing';
 import {AppConfigService, ConfigurationService} from './service';
-import {HttpClient, HttpHandler} from '@angular/common/http';
-import {TranslateService, TranslateModule, TranslateLoader, MissingTranslationHandler} from '@ngx-translate/core';
-import {TranslateFakeLoader} from '@ngx-translate/core';
+import {MissingTranslationHandler, TranslateFakeLoader, TranslateLoader, TranslateModule, TranslateService} from '@ngx-translate/core';
 import {Observable, of} from 'rxjs';
 import {Configuration} from './model/configuration';
 import {CustomMissingTranslationService} from './i18n/custommissingtranslation.service';
@@ -14,75 +12,104 @@ import {AuthService} from './auth/auth.service';
 import {JwtHelperService, JwtModule} from '@auth0/angular-jwt';
 import {ServiceUnavailableService} from './service-unavailable/service-unavailable.service';
 import {SharedModule} from './shared';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
 
 class MockConfigurationService {
-  protected uri: string;
+    protected uri: string;
 
-  constructor() {
-    this.uri = 'http://localhost/api';
-  }
+    constructor() {
+        this.uri = 'http://localhost/api';
+    }
 
-  public getApiUrl(): string {
-    return 'http://localhost/api';
-  }
+    public getApiUrl(): string {
+        return 'http://localhost/api';
+    }
 
-  public getConfiguration(): Observable<Configuration> {
-    return of<Configuration>();
-  }
+    public getConfiguration(): Observable<Configuration> {
+        return of<Configuration>();
+    }
 
-  public updateConfiguration(configuration: Configuration): Observable<any> {
-    return of<Configuration>();
-  }
+    public updateConfiguration(configuration: Configuration): Observable<any> {
+        return of<Configuration>();
+    }
 }
 
+class MockAppConfigService {
+    config: any;
+  
+    constructor() { }
+  
+    public load() {
+    }
+  
+    public getApiUrl(): string {
+      return '';
+    }
+  
+    public getNmaasGlobalDomainId(): number {
+      return 0;
+    }
+  
+    public getHttpTimeout(): number {
+      return 10000;
+    }
+  
+    public getShowGitInfo(): boolean {
+      return false;
+    }
+  
+    public getShowChangelog(): boolean {
+      return false;
+    }
+  }
+
 class MockServiceUnavailableService {
-  public isServiceAvailable: boolean;
+    public isServiceAvailable: boolean;
 
-  constructor() {
-    this.isServiceAvailable = true;
-  }
+    constructor() {
+        this.isServiceAvailable = true;
+    }
 }
 
 describe('App: NmaasPortal', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      declarations: [
-        AppComponent
-      ],
-        imports: [
-            RouterTestingModule,
-            TranslateModule.forRoot({
-                missingTranslationHandler: {provide: MissingTranslationHandler, useClass: CustomMissingTranslationService},
-                loader: {
-                    provide: TranslateLoader,
-                    useClass: TranslateFakeLoader
-                }
-            }),
-            JwtModule.forRoot({
-                config: {
-                    tokenGetter: () => {
-                        return '';
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            declarations: [
+                AppComponent
+            ],
+            imports: [
+                HttpClientTestingModule,
+                RouterTestingModule,
+                TranslateModule.forRoot({
+                    missingTranslationHandler: {provide: MissingTranslationHandler, useClass: CustomMissingTranslationService},
+                    loader: {
+                        provide: TranslateLoader,
+                        useClass: TranslateFakeLoader
+                    }
+                }),
+                JwtModule.forRoot({
+                    config: {
+                        tokenGetter: () => {
+                            return '';
+                        }
                     }
-                }
-            }),
-          SharedModule
-        ],
-        providers: [
-            {provide: AppConfigService, useClass: MockConfigurationService},
-            HttpClient,
-            HttpHandler,
-            ConfigurationService,
-            TranslateService,
-            AuthService,
-            JwtHelperService,
-            {provide: ServiceUnavailableService, useClass: MockServiceUnavailableService}
-        ]
+                }),
+                SharedModule
+            ],
+            providers: [
+                {provide: AppConfigService, useClass: MockAppConfigService},
+                {provide: ConfigurationService, useClass: MockConfigurationService},
+                TranslateService,
+                AuthService,
+                JwtHelperService,
+                {provide: ServiceUnavailableService, useClass: MockServiceUnavailableService}
+            ]
+        });
     });
-  });
 
-  it('should create the app', waitForAsync(() => {
-    const fixture = TestBed.createComponent(AppComponent);
-    const app = fixture.debugElement.componentInstance;
-    expect(app).toBeTruthy();
-  }));
+    it('should create the app', waitForAsync(() => {
+        const fixture = TestBed.createComponent(AppComponent);
+        const app = fixture.debugElement.componentInstance;
+        expect(app).toBeTruthy();
+    }));
 });
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index 610c10ccf5c6a61d2610e4be2b3fdefe9e51fcde..31a968fec3b241c1d54e3257898a92a6e781fe71 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -6,6 +6,7 @@ import { WelcomeRoutes } from './welcome/welcome.routes';
 import {ServiceUnavailableRoutes} from './service-unavailable/service-unavailable.routes';
 import {PageNotFoundComponent} from './shared/page-not-found/page-not-found.component';
 import {LoginSuccessComponent} from './auth/login-success/login-success.component';
+import {LinkAccountComponent} from './welcome/link-account/link-account.component';
 
 const appRoutes: Routes = [
     ...WelcomeRoutes,
@@ -13,6 +14,7 @@ const appRoutes: Routes = [
     ...ServiceUnavailableRoutes,
     { path: 'notfound', component: PageNotFoundComponent },
     { path: 'login-success', component: LoginSuccessComponent },
+    { path: 'login-linking', component: LinkAccountComponent},
     { path: '**', redirectTo: '/welcome' },
 
 ];
diff --git a/src/app/appmarket/admin/clusters/details/clusterdetails.component.html b/src/app/appmarket/admin/clusters/details/clusterdetails.component.html
index b5730cb4b9e56571b219092a7e57e10fe0a5bc8e..bed274174116378cf2e63aabfa68b5bfaec37345 100644
--- a/src/app/appmarket/admin/clusters/details/clusterdetails.component.html
+++ b/src/app/appmarket/admin/clusters/details/clusterdetails.component.html
@@ -1 +1 @@
-<nmaas-clusterdetails class="col-sm-12 col-sm-12 col-md-12" [cluster]="cluster" [error]="error" [mode]="getCurrentMode()" [allowedModes]="[ComponentMode.VIEW, ComponentMode.CREATE]" (onSave)="onSave($event)" (onDelete)="onDelete($event)"></nmaas-clusterdetails>
+<nmaas-clusterdetails class="col-sm-12 col-sm-12 col-md-12" [cluster]="cluster" [error]="error" [mode]="getCurrentMode()" [allowedModes]="[ComponentMode.VIEW, ComponentMode.CREATE]"></nmaas-clusterdetails>
diff --git a/src/app/appmarket/admin/clusters/details/clusterdetails.component.ts b/src/app/appmarket/admin/clusters/details/clusterdetails.component.ts
index 248a6943e8c8662468fd62f1dad8c0833908ba1d..d9990a60a4ed7bf7effaebbf62dce13b1bcd63c4 100644
--- a/src/app/appmarket/admin/clusters/details/clusterdetails.component.ts
+++ b/src/app/appmarket/admin/clusters/details/clusterdetails.component.ts
@@ -29,21 +29,4 @@ export class ClusterDetailsComponent extends BaseComponent implements OnInit {
         });
     }
 
-    public onSave($event) {
-        const upCluster: Cluster = $event;
-        if (!upCluster) {
-            return;
-        }
-        if (this.isInMode(ComponentMode.CREATE)) {
-            this.clusterService.add(upCluster)
-                .subscribe(() => this.router.navigateByUrl('/admin/clusters'), err => this.error = err.message);
-        } else {
-            this.clusterService.update(upCluster)
-                .subscribe(() => this.router.navigateByUrl('/admin/clusters'), err => this.error = err.message);
-        }
-    }
-
-    public onDelete($event): void {
-        this.clusterService.remove($event).subscribe(() => this.router.navigate(['/admin/clusters/']));
-    }
 }
diff --git a/src/app/appmarket/admin/configuration/details/configurationdetails.component.html b/src/app/appmarket/admin/configuration/details/configurationdetails.component.html
index 92aafcd35ac0b0fe8ffbd4b30836afee1c5b256e..30c84ce7fe97321197b2faa778088dd1a7e6df4f 100644
--- a/src/app/appmarket/admin/configuration/details/configurationdetails.component.html
+++ b/src/app/appmarket/admin/configuration/details/configurationdetails.component.html
@@ -131,6 +131,39 @@
                     
                     </div>
                 </div>
+                <div class="form-group">
+                    <label for="bulkDeploymentQueueRefresh"
+                           class="col-sm-3 control-label">{{'PORTAL_CONFIGURATION.BULK_DEPLOYMENT_QUEUE_REFRESH' | translate}}</label>
+                    <div class="col-sm-9 pd-top-7">
+                        <div class="input-width">
+                            <input class="form-control" type="number" id="bulkDeploymentQueueRefresh" name="bulkDeploymentQueueRefresh"
+                            [(ngModel)]="this.configuration.bulkDeploymentQueueRefresh">
+                        </div>
+                    
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label for="bulkDeploymentTimeThreshold"
+                           class="col-sm-3 control-label">{{'PORTAL_CONFIGURATION.BULK_DEPLOYMENT_THRESHOLD' | translate}}</label>
+                    <div class="col-sm-9 pd-top-7">
+                        <div class="input-width">
+                            <input class="form-control" type="number" id="bulkDeploymentTimeThreshold" name="bulkDeploymentTimeThreshold"
+                            [(ngModel)]="this.configuration.bulkDeploymentTimeThreshold">
+                        </div>
+                    
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label for="deploymentPrefix"
+                           class="col-sm-3 control-label">{{'PORTAL_CONFIGURATION.DEPLOYMENT_PREFIX' | translate}}</label>
+                    <div class="col-sm-9 pd-top-7">
+                        <div class="input-width">
+                            <input class="form-control" type="text" id="deploymentPrefix" name="deploymentPrefix"
+                            [(ngModel)]="this.configuration.deploymentPrefix">
+                        </div>
+                    
+                    </div>
+                </div>
                 <div class="flex justify-content-end">
                     <button class="btn btn-primary"
                             type="submit">{{ 'PORTAL_CONFIGURATION.SUBMIT_BUTTON' | translate }}</button>
diff --git a/src/app/appmarket/appdetails/appdetails.component.html b/src/app/appmarket/appdetails/appdetails.component.html
index 4ba9674e295eeb8528aeb7426f08f1dbeea2cf49..bb2bbfff4d2c1ff653f1c8dc6942bb1ef5bc55eb 100644
--- a/src/app/appmarket/appdetails/appdetails.component.html
+++ b/src/app/appmarket/appdetails/appdetails.component.html
@@ -43,7 +43,7 @@
 			<div class="row" *ngIf="versionVisible">
 				<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6" *ngIf="activeVersions">
 					<a *ngFor="let version of activeVersions" class="tag-button">
-						v.{{version}}
+						v{{version}}
 					</a>
 				</div>
 			</div>
diff --git a/src/app/appmarket/appinstance/appinstance/appinstance.component.html b/src/app/appmarket/appinstance/appinstance/appinstance.component.html
index 330151db9ebe9fe0c3741dec40f339e289153372..201b7698f8ab91f85596ecee8465ed82aa0aa563 100644
--- a/src/app/appmarket/appinstance/appinstance/appinstance.component.html
+++ b/src/app/appmarket/appinstance/appinstance/appinstance.component.html
@@ -95,7 +95,7 @@
                         <ul class="dropdown-menu">
                             <ng-container *ngIf="getStateAsEnum(appInstanceStatus?.state) === AppInstanceState.RUNNING">
                                 <li>
-                                    <a role="button" (click)="this.accessMethodsModal.show()">
+                                    <a role="button" (click)="openAccessMethodsModal()">
                                         {{'APP_INSTANCE.APP_ACCESS_METHODS' | translate}}
                                     </a>
                                 </li>
diff --git a/src/app/appmarket/appinstance/appinstance/appinstance.component.spec.ts b/src/app/appmarket/appinstance/appinstance/appinstance.component.spec.ts
index 742069adfd21e9f305a3b14ceb8ccbbdcdf4c0ae..449459e4f4b881d437f763ae6433b6b45ad4b7b7 100644
--- a/src/app/appmarket/appinstance/appinstance/appinstance.component.spec.ts
+++ b/src/app/appmarket/appinstance/appinstance/appinstance.component.spec.ts
@@ -13,7 +13,6 @@ import {NgxPaginationModule} from 'ngx-pagination';
 import {AppRestartModalComponent} from '../modals/app-restart-modal';
 import {AppAbortModalComponent} from '../modals/app-abort-modal';
 import {RouterTestingModule} from '@angular/router/testing';
-import {StorageServiceModule} from 'ngx-webstorage-service';
 import {AppInstanceState, User} from '../../../model';
 import {Role} from '../../../model/userrole';
 import {ServiceAccessMethodType} from '../../../model/service-access-method';
@@ -272,7 +271,6 @@ describe('Component: AppInstance', () => {
                 PipesModule,
                 FormioModule,
                 RouterTestingModule,
-                StorageServiceModule,
                 JwtModule.forRoot({}),
                 TranslateModule.forRoot({
                     loader: {
diff --git a/src/app/appmarket/appinstance/appinstance/appinstance.component.ts b/src/app/appmarket/appinstance/appinstance/appinstance.component.ts
index c4ce87cd4c01e91f4f95949c30428da0c5ec570d..543a563ff26a4089231b8e225fbcc4512120f17c 100644
--- a/src/app/appmarket/appinstance/appinstance/appinstance.component.ts
+++ b/src/app/appmarket/appinstance/appinstance/appinstance.component.ts
@@ -164,8 +164,6 @@ export class AppInstanceComponent implements OnInit, OnDestroy {
                     this.configurationTemplate = this.getTemplate(appInstance.configWizardTemplate.template);
                     this.app = appInstance.application;
 
-                    this.updateAppInstancePodNames();
-
                     this.submission.data.configuration = JSON.parse(appInstance.configuration);
 
                     if (this.appInstance.configUpdateWizardTemplate != null) {
@@ -645,4 +643,13 @@ export class AppInstanceComponent implements OnInit, OnDestroy {
     }
 
 
+    public openAccessMethodsModal(): void {
+        this.appInstanceService.getDeploymentParameters(this.appInstanceId).subscribe(
+            deployParams => {
+                this.deployParametersSubject.next(deployParams)
+                this.accessMethodsModal.show()   ;
+    })
+      
+    }
+
 }
diff --git a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html
index 72fd4db5ee3d8ae828654970a253fc669cc7b7ca..3771d215733c6678848010cdfda44529fe087dd0 100644
--- a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html
+++ b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.html
@@ -536,6 +536,7 @@
                             <form-builder *ngIf="formDisplayChange && applicationDTO.application.configWizardTemplate.template"
                                           [form]="applicationDTO.application.configWizardTemplate.template" (change)="setConfigTemplate($event)">
                             </form-builder>
+                           
                         </p-tabPanel>
 
                         <p-tabPanel header="{{'APPS_WIZARD.RAW_JSON' | translate}}">
diff --git a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts
index e9e30b6449f6c4154ed1f3e679754a5d17c26636..90f3e447abb68f69f83746904b7a43dc3712885e 100644
--- a/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts
+++ b/src/app/appmarket/appmanagement/app-create-wizard/app-create-wizard.component.ts
@@ -1,4 +1,4 @@
-import {Component, OnInit, ViewChild, ViewEncapsulation} from '@angular/core';
+import {Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation} from '@angular/core';
 import {ConfigWizardTemplate} from '../../../model';
 import {MenuItem, SelectItem} from 'primeng/api';
 import {AppImagesService, AppsService, TagService} from '../../../service';
@@ -29,7 +29,7 @@ import {ApplicationBase} from '../../../model/application-base';
     styleUrls: ['./app-create-wizard.component.css']
 })
 
-export class AppCreateWizardComponent extends BaseComponent implements OnInit {
+export class AppCreateWizardComponent extends BaseComponent implements OnInit, OnDestroy {
 
     @ViewChild(ModalComponent, {static: true})
     public modal: ModalComponent;
@@ -59,6 +59,9 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
     public languages: SelectItem[] = [];
     public formDisplayChange = true;
 
+    public template : any;
+    public translateUpdate: any;
+
     // properties for global parameters deploy validation
     // in future extensions pack this into single object
     public deployParamKeyValidator: ValidatorFn = noParameterTypeInControlValueValidator();
@@ -97,6 +100,7 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
         }));
         this.getParametersTypes().forEach(val => this.deployParameter.push({label: val.replace('_', ' '), value: val}));
         this.steps = this.getSteps();
+        this.updateStepsTranslation();
         this.route.params.subscribe(params => {
             if (params['id'] == null) {
                 this.createNewWizard();
@@ -120,6 +124,25 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
         });
     }
 
+    private updateStepsTranslation() {
+        this.translateUpdate = setInterval(() => {
+            if(this.translate.instant('APPS_WIZARD.GENERAL_INFO_STEP') !== null) {
+                this.steps = this.getSteps();
+                this.stopTranslationUpdate();
+            }
+        }, 200);
+    }
+
+    private stopTranslationUpdate() {
+        clearInterval(this.translateUpdate);
+        this.translateUpdate = null;
+    }
+
+    ngOnDestroy(): void {
+        clearInterval(this.translateUpdate);
+        this.translateUpdate = null;
+    }
+
     public getSteps(): any {
         if (this.isInMode(ComponentMode.CREATE)) {
             return [
@@ -206,7 +229,8 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
         this.configFileTemplates.push(new ConfigFileTemplate());
         this.applicationDTO.application.configWizardTemplate = new ConfigWizardTemplate();
         this.applicationDTO.application.configWizardTemplate.template = this.configTemplateService.getConfigTemplate();
-    }
+    };
+    
 
     public nextStep(): void {
         this.activeStepIndex += 1;
@@ -325,10 +349,15 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
     }
 
     public setConfigTemplate(event): void {
-        if (!this.applicationDTO.application.configWizardTemplate) {
-            this.applicationDTO.application.configWizardTemplate = new ConfigWizardTemplate();
+      console.log(event)
+        if(event.type === "addComponent" || event.type === "saveComponent") {
+            console.log(event);
+            this.template = event.form;
+            this.applicationDTO.application.configWizardTemplate.template = null;
+            this.applicationDTO.application.configWizardTemplate.template = Object.assign({}, this.template);
+            console.log('Wizard saved',this.applicationDTO.application.configWizardTemplate.template)
         }
-        this.applicationDTO.application.configWizardTemplate.template = event.form;
+       
     }
 
     public setUpdateConfigTemplate(event): void {
@@ -539,7 +568,7 @@ export class AppCreateWizardComponent extends BaseComponent implements OnInit {
         if (this.applicationDTO.application.appConfigurationSpec.configFileRepositoryRequired) {
             this.removeDefaultElement();
         } else {
-            this.addDefaultElement();
+            // this.addDefaultElement();
             this.removeElementsFromUpdateConfig();
         }
     }
diff --git a/src/app/appmarket/appmanagement/app-management.routes.ts b/src/app/appmarket/appmanagement/app-management.routes.ts
index 3a38b22f99228ccae091e7ab302d6140d07ace95..5b7f58eb2b73e13b934ae3e02a10e43d5cc20201 100644
--- a/src/app/appmarket/appmanagement/app-management.routes.ts
+++ b/src/app/appmarket/appmanagement/app-management.routes.ts
@@ -54,7 +54,7 @@ export const AppManagementRoutes: Route[] = [
         path: 'admin/apps/bulks',
         component: BulkAppListComponent,
         canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     { path: 'admin/apps/bulks/new',
         component: AppnavigatorComponent,
@@ -68,6 +68,6 @@ export const AppManagementRoutes: Route[] = [
         path: 'admin/apps/bulks/:id',
         component: BulkViewComponent,
         canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER' ]}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER' ]}
     },
 ];
diff --git a/src/app/appmarket/appmanagement/app-version-create-wizard/app-version-create-wizard.component.ts b/src/app/appmarket/appmanagement/app-version-create-wizard/app-version-create-wizard.component.ts
index b964ab330bbac1b623b4390ecba870329d4b1e95..d4f6b6c6b18513c382a8d9605ca5a20a943246a5 100644
--- a/src/app/appmarket/appmanagement/app-version-create-wizard/app-version-create-wizard.component.ts
+++ b/src/app/appmarket/appmanagement/app-version-create-wizard/app-version-create-wizard.component.ts
@@ -1,25 +1,25 @@
-import {Component, OnInit, ViewChild} from '@angular/core';
-import {BaseComponent} from '../../../shared/common/basecomponent/base.component';
-import {ModalComponent} from '../../../shared';
-import {ConfigWizardTemplate} from '../../../model';
-import {ConfigFileTemplate} from '../../../model/configfiletemplate';
-import {AppImagesService, AppsService} from '../../../service';
-import {ActivatedRoute, Router} from '@angular/router';
-import {ConfigTemplateService} from '../../../service/configtemplate.service';
-import {ParameterType} from '../../../model/parametertype';
-import {KubernetesTemplate} from '../../../model/kubernetes-template';
-import {TranslateService} from '@ngx-translate/core';
-import {DomSanitizer} from '@angular/platform-browser';
-import {ApplicationState} from '../../../model/application-state';
-import {KubernetesChart} from '../../../model/kuberneteschart';
-import {AppStorageVolume} from '../../../model/app-storage-volume';
-import {parseServiceStorageVolumeType, ServiceStorageVolumeType} from '../../../model/service-storage-volume';
-import {AppAccessMethod} from '../../../model/app-access-method';
-import {parseServiceAccessMethodType, ServiceAccessMethodType} from '../../../model/service-access-method';
-import {AbstractControl, ValidatorFn} from '@angular/forms';
-import {MultiSelect} from 'primeng/multiselect';
-import {MenuItem, SelectItem} from 'primeng/api';
-import {ApplicationDTO} from '../../../model/application-dto';
+import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { BaseComponent } from '../../../shared/common/basecomponent/base.component';
+import { ModalComponent } from '../../../shared';
+import { ConfigWizardTemplate } from '../../../model';
+import { ConfigFileTemplate } from '../../../model/configfiletemplate';
+import { AppImagesService, AppsService } from '../../../service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ConfigTemplateService } from '../../../service/configtemplate.service';
+import { ParameterType } from '../../../model/parametertype';
+import { KubernetesTemplate } from '../../../model/kubernetes-template';
+import { TranslateService } from '@ngx-translate/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { ApplicationState } from '../../../model/application-state';
+import { KubernetesChart } from '../../../model/kuberneteschart';
+import { AppStorageVolume } from '../../../model/app-storage-volume';
+import { parseServiceStorageVolumeType, ServiceStorageVolumeType } from '../../../model/service-storage-volume';
+import { AppAccessMethod } from '../../../model/app-access-method';
+import { parseServiceAccessMethodType, ServiceAccessMethodType } from '../../../model/service-access-method';
+import { AbstractControl, ValidatorFn } from '@angular/forms';
+import { MultiSelect } from 'primeng/multiselect';
+import { MenuItem, SelectItem } from 'primeng/api';
+import { ApplicationDTO } from '../../../model/application-dto';
 import { ApplicationVersion } from '../../../model/application-version';
 import * as semver from 'semver';
 import { Application } from '../../../model/application';
@@ -34,7 +34,7 @@ export function noParameterTypeInControlValueValidator(): ValidatorFn {
         }
         const notValid = labels.filter(val => control.value.includes(val)).length === 0;
         console.log('checking: ', control.value, 'valid: ', !notValid);
-        return notValid ? {'noParameterTypeInControlValue': {value: control.value}} : null;
+        return notValid ? { 'noParameterTypeInControlValue': { value: control.value } } : null;
     };
 }
 
@@ -43,10 +43,10 @@ export function noParameterTypeInControlValueValidator(): ValidatorFn {
     templateUrl: './app-version-create-wizard.component.html',
     styleUrls: ['./app-version-create-wizard.component.css']
 })
-export class AppVersionCreateWizardComponent extends BaseComponent implements OnInit {
+export class AppVersionCreateWizardComponent extends BaseComponent implements OnInit, OnDestroy {
 
 
-    @ViewChild(ModalComponent, {static: true})
+    @ViewChild(ModalComponent, { static: true })
     public modal: ModalComponent;
 
     @ViewChild('tagsMultiSelect')
@@ -68,7 +68,9 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
     public logo: any[] = [];
     public screenshots: any[] = [];
     public applicationVersions: ApplicationVersion[] = [];
-    public selectedVersion : any ;
+    public selectedVersion: any;
+    public template: any;
+    public translateUpdate: any;
 
     // properties for global parameters deploy validation
     // in future extensions pack this into single object
@@ -83,12 +85,12 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
     };
 
     constructor(public appsService: AppsService,
-                public route: ActivatedRoute,
-                public translate: TranslateService,
-                public dom: DomSanitizer,
-                public configTemplateService: ConfigTemplateService,
-                public router: Router,
-                public appImagesService: AppImagesService) {
+        public route: ActivatedRoute,
+        public translate: TranslateService,
+        public dom: DomSanitizer,
+        public configTemplateService: ConfigTemplateService,
+        public router: Router,
+        public appImagesService: AppImagesService) {
         super();
     }
 
@@ -97,14 +99,21 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
         this.modal.setModalType('success');
         this.modal.setStatusOfIcons(false);
         this.mode = this.getMode(this.route);
-        this.getParametersTypes().forEach(val => this.deployParameter.push({label: val.replace('_', ' '), value: val}));
-        this.steps = [
-            {label: this.translate.instant('APPS_WIZARD.GENERAL_INFO_STEP')},
-            {label: this.translate.instant('APPS_WIZARD.BASIC_APP_INFO_STEP')},
-            {label: this.translate.instant('APPS_WIZARD.APP_DEPLOYMENT_SPEC_STEP')},
-            {label: this.translate.instant('APPS_WIZARD.CONFIG_TEMPLATES_STEP')},
-            {label: this.translate.instant('APPS_WIZARD.SHORT_REVIEW_STEP')}
-        ];
+        this.getParametersTypes().forEach(val => this.deployParameter.push({ label: val.replace('_', ' '), value: val }));
+        //trick to avoid using this.translate.onChange cuz its not working on current angular without changing language 
+        this.translateUpdate = setInterval(() => {
+            if(this.translate.instant('APPS_WIZARD.GENERAL_INFO_STEP') !== null) {
+                this.steps = [
+                    { label: this.translate.instant('APPS_WIZARD.GENERAL_INFO_STEP') },
+                    { label: this.translate.instant('APPS_WIZARD.BASIC_APP_INFO_STEP') },
+                    { label: this.translate.instant('APPS_WIZARD.APP_DEPLOYMENT_SPEC_STEP') },
+                    { label: this.translate.instant('APPS_WIZARD.CONFIG_TEMPLATES_STEP') },
+                    { label: this.translate.instant('APPS_WIZARD.SHORT_REVIEW_STEP') }
+                ];
+                this.stopTranslationUpdate();
+            }
+        }, 200);
+
         this.route.params.subscribe(params => {
             const appName = params['name']
             const appId = params['id']
@@ -137,6 +146,16 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
         });
     }
 
+    private stopTranslationUpdate() {
+        clearInterval(this.translateUpdate);
+        this.translateUpdate = null;
+    }
+
+    ngOnDestroy(): void {
+        clearInterval(this.translateUpdate);
+        this.translateUpdate = null;
+    }
+
     public appVersionCompare(a: ApplicationVersion, b: ApplicationVersion): number {
         // defaults version that cannot be parsed to `0.0.0`
         return semver.compare(semver.coerce(b.version) || '0.0.0', semver.coerce(a.version) || '0.0.0')
@@ -238,10 +257,13 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
     }
 
     public setConfigTemplate(event): void {
-        if (!this.applicationDTO.application.configWizardTemplate) {
-            this.applicationDTO.application.configWizardTemplate = new ConfigWizardTemplate();
+        if (event.type === "addComponent" || event.type === "saveComponent") {
+            console.log(event);
+            this.template = event.form;
+            this.applicationDTO.application.configWizardTemplate.template = null;
+            this.applicationDTO.application.configWizardTemplate.template = Object.assign({}, this.template);
+            console.log('Wizard saved', this.applicationDTO.application.configWizardTemplate.template)
         }
-        this.applicationDTO.application.configWizardTemplate.template = event.form;
     }
 
     public setUpdateConfigTemplate(event): void {
@@ -494,7 +516,7 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
     }
 
     private convertToProperImageFile(file: any) {
-        const result: any = new File([file], 'uploaded file', {type: file.type});
+        const result: any = new File([file], 'uploaded file', { type: file.type });
         result.objectURL = this.dom.bypassSecurityTrustUrl(URL.createObjectURL(result));
         return result;
     }
@@ -545,7 +567,7 @@ export class AppVersionCreateWizardComponent extends BaseComponent implements On
     }
 
     public onVersionSelect(event: any) {
-        console.log("Slected version ",event )
+        console.log("Slected version ", event)
         this.appsService.getApplication(event.value.appVersionId).subscribe(data => {
             console.log(data);
             this.applicationDTO.application = data;
diff --git a/src/app/appmarket/appmanagement/json-edit/json-edit.component.ts b/src/app/appmarket/appmanagement/json-edit/json-edit.component.ts
index e92e8eaf211d700684c6b23b62d3b405d147f609..0cbc671cfff9fc0fb5c8262285c57b1f0ae9b77a 100644
--- a/src/app/appmarket/appmanagement/json-edit/json-edit.component.ts
+++ b/src/app/appmarket/appmanagement/json-edit/json-edit.component.ts
@@ -28,7 +28,6 @@ export class JsonEditComponent {
 
   @Input()
   set object(obj: any) {
-    console.log('setting value')
     const contentString = JSON.stringify(obj, null, 2);
     if (this.content && contentString !== this.content.value) {
       this.content.setValue(contentString)
diff --git a/src/app/appmarket/appmarket.module.ts b/src/app/appmarket/appmarket.module.ts
index 8bd9ce86288da65d981ac9fe9af4363df7b433b3..1539264532ea45f31fb58cb059887338c5cecf57 100644
--- a/src/app/appmarket/appmarket.module.ts
+++ b/src/app/appmarket/appmarket.module.ts
@@ -21,7 +21,6 @@ import {ClustersModule} from './admin/clusters/clusters.module';
 import {ClusterService} from '../service/cluster.service';
 import {ConfigurationModule} from './admin/configuration/configuration.module';
 import {MonitorModule} from './admin/monitor/monitor.module';
-import {StorageServiceModule} from 'ngx-webstorage-service';
 import {TranslateModule} from '@ngx-translate/core';
 import {HttpClientModule} from '@angular/common/http';
 import {BrowserModule} from '@angular/platform-browser';
@@ -48,6 +47,12 @@ import {NgxPaginationModule} from 'ngx-pagination';
 import {InputTextModule} from 'primeng/inputtext';
 import {BulkSearchPipe} from './bulkDeployment/bulk-list/bulk-search.pipe';
 import {CheckboxModule} from 'primeng/checkbox';
+import { InputSwitchModule } from 'primeng/inputswitch';
+import { OverlayPanelModule } from 'primeng/overlaypanel';
+import { SidebarModule } from 'primeng/sidebar';
+import { ProgressBarModule } from 'primeng/progressbar';
+
+
 
 @NgModule({
     declarations: [
@@ -66,7 +71,6 @@ import {CheckboxModule} from 'primeng/checkbox';
     ],
     imports: [
         FormsModule,
-        StorageServiceModule,
         CommonModule,
         RouterModule,
         SharedModule,
@@ -94,6 +98,10 @@ import {CheckboxModule} from 'primeng/checkbox';
         InputTextModule,
         TooltipModule,
         CheckboxModule,
+        InputSwitchModule,
+        OverlayPanelModule,
+        SidebarModule,
+        ProgressBarModule
     ],
     exports: [
         AppMarketComponent,
diff --git a/src/app/appmarket/bulkDeployment/appdeployment.service.ts b/src/app/appmarket/bulkDeployment/appdeployment.service.ts
index 0d4d728735e3e38d36eec79bcae0b6827d6b9ed2..f660f0531c4ff76f1c92041d070d6205ced673fe 100644
--- a/src/app/appmarket/bulkDeployment/appdeployment.service.ts
+++ b/src/app/appmarket/bulkDeployment/appdeployment.service.ts
@@ -5,6 +5,7 @@ import {AppConfigService} from '../../service';
 import {BulkResponse} from '../../model/bulk-response';
 import {Observable} from 'rxjs';
 import {BulkDeployment} from '../../model/bulk-deployment';
+import { BulkQueueDetails } from '../../model/bulk-queue-details';
 
 @Injectable({
     providedIn: 'root'
@@ -71,20 +72,24 @@ export class AppdeploymentService {
         return this.http.post<BulkDeployment>(this.getUrl() + 'domains', formParams);
     }
 
-    public getBulksDomainDeployments(): Observable<BulkDeployment[]> {
-        return this.http.get<BulkDeployment[]>(this.getUrl() + 'domains');
+    public getBulksDomainDeployments(showDeleted: boolean = false): Observable<BulkDeployment[]> {
+        const formParams = new HttpParams().append('deleted', showDeleted);
+    
+        return this.http.get<BulkDeployment[]>(this.getUrl() + 'domains', {params:formParams});
     }
 
     public getBulksDomainDeploymentsOwner(): Observable<BulkDeployment[]> {
-        return this.http.get<BulkDeployment[]>(this.getUrl() + 'domains/vl');
+        return this.http.get<BulkDeployment[]>(this.getUrl() + 'domains/group');
     }
 
-    public getBulksAppDeployments(): Observable<BulkDeployment[]> {
-        return this.http.get<BulkDeployment[]>(this.getUrl() + 'apps');
+    public getBulksAppDeployments(showDeleted: boolean = false): Observable<BulkDeployment[]> {
+        const formParams = new HttpParams().append('deleted', showDeleted);
+
+        return this.http.get<BulkDeployment[]>(this.getUrl() + 'apps', {params:formParams});
     }
 
     public getBulksAppDeploymentsOwner(): Observable<BulkDeployment[]> {
-        return this.http.get<BulkDeployment[]>(this.getUrl() + 'apps/vl');
+        return this.http.get<BulkDeployment[]>(this.getUrl() + 'apps/group');
     }
 
     public getBulkDeployment(id: number): Observable<BulkDeployment> {
@@ -104,4 +109,9 @@ export class AppdeploymentService {
         return this.http.delete(this.getUrl() +`${id}`, { params });
     }
 
+    public getQueueDetails(id: number) : Observable<BulkQueueDetails> {
+        return this.http.get<BulkQueueDetails>(this.getUrl() + `queue/${id}`)
+    }
+
+
 }
diff --git a/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.html b/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.html
index e34eee5938d37ec4330b3cd1f1ebdc2d9659707f..340557d5220556e32498ffcac2549231bde94c23 100644
--- a/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.html
+++ b/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.html
@@ -1,2 +1,2 @@
-<app-bulk-list [header]="'BULK.APP.HEADER'" [bulks]="bulks" [mode]="mode"></app-bulk-list>
+<app-bulk-list [header]="'BULK.APP.HEADER'" [bulks]="bulks" [mode]="mode" (refresh)="onRefresh($event)"></app-bulk-list>
 
diff --git a/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.ts b/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.ts
index 9256cfa4ea2a99172b68b96471a1312b92bb206d..7b89c6899bce5d8dbe07c971fd8601093a27d2fc 100644
--- a/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.ts
+++ b/src/app/appmarket/bulkDeployment/bulk-app-list/bulk-app-list.component.ts
@@ -20,16 +20,20 @@ export class BulkAppListComponent implements OnInit {
     }
 
     ngOnInit(): void {
-        if (this.authService.getRoles().find(value => value === 'ROLE_VL_MANAGER') !== undefined) {
+     this.onRefresh();
+    }
+
+    onRefresh(showDeleted = false) : void {
+        if (this.authService.getRoles().find(value => value === 'ROLE_GROUP_MANAGER') !== undefined) {
             this.deployService.getBulksAppDeploymentsOwner().subscribe(data => {
                 data = data.sort((a, b) => new Date(b.creationDate).getTime() - new Date(a.creationDate).getTime())
                 this.bulks = data
             });
         } else {
-            this.deployService.getBulksAppDeployments().subscribe(data => {
+            this.deployService.getBulksAppDeployments(showDeleted).subscribe(data => {
                 data = data.sort((a, b) => new Date(b.creationDate).getTime() - new Date(a.creationDate).getTime())
                 this.bulks = data
             });
         }
     }
-}
+ }
diff --git a/src/app/appmarket/bulkDeployment/bulk-domain-list/bulk-domain-list.component.ts b/src/app/appmarket/bulkDeployment/bulk-domain-list/bulk-domain-list.component.ts
index 696e86a9f8ccc30a4615d7e13af798cd423e4651..cfd2fe6751732bde31b6ef9e5553bb53b20e1a5f 100644
--- a/src/app/appmarket/bulkDeployment/bulk-domain-list/bulk-domain-list.component.ts
+++ b/src/app/appmarket/bulkDeployment/bulk-domain-list/bulk-domain-list.component.ts
@@ -20,7 +20,7 @@ export class BulkDomainListComponent implements OnInit {
     }
 
     ngOnInit(): void {
-        if (this.authService.getRoles().find(value => value === 'ROLE_VL_MANAGER') !== undefined) {
+        if (this.authService.getRoles().find(value => value === 'ROLE_GROUP_MANAGER') !== undefined) {
             this.deployService.getBulksDomainDeploymentsOwner().subscribe(data => {
                 data = data.sort((a, b) => new Date(b.creationDate).getTime() - new Date(a.creationDate).getTime())
                 this.bulks = data
diff --git a/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.html b/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.html
index 04d746b77637cdfbe1ba345029160948e7452ea0..d974dc0a1a2154e5679a4c39d6efd633d8839c0a 100644
--- a/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.html
+++ b/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.html
@@ -7,7 +7,40 @@
         <div *ngIf="mode=== bulkTypeApp">
             <button class="btn btn-primary" [routerLink]="['/admin/apps/bulks/new']">New deployment</button>
         </div>
+        
         <div class="flex">
+            <div  *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']"  class="flex align-items-center mr-6">
+        
+                <p-button 
+                    type="button" 
+                    class="mr-2" 
+                    (onClick)="sidebarVisible4 = true" 
+                    label="Deployments Queue"
+                    severity="secondary"
+                     ></p-button>
+                <p-sidebar [(visible)]="sidebarVisible4" position="left" styleClass="w-30rem">
+                    <h3>Deployments Queue</h3>
+                    <div class="flex flex-column">
+                        <div class="flex grid">
+                            <label class="col-10" for="jobInQueue">Jobs in queue</label>
+                            <span class="col-2 " id="jobInQueue">{{queueDetails?.jobInQueue}}</span>
+                        </div>
+                        <div class="flex grid">
+                            <label class="col-10" for="jobInProcess">In progress</label>
+                            <span class="col-2 " id="jobInProcess">{{queueDetails?.jobInProcess}}</span>
+                        </div>
+                        <div class="flex grid">
+                            <label class="col-10" for="jobInProcessId">Current proccessing bulk id</label>
+                            <span class="col-2" id="jobInProcessId">{{queueDetails?.jobInProcessId}}</span>
+                        </div>
+                    </div>
+                </p-sidebar>
+                
+            </div>
+            <div  *roles="['ROLE_SYSTEM_ADMIN']"  class="flex align-items-center mr-6 pt-2">
+                <label  *ngIf="mode=== bulkTypeApp" class="mr-2" for="showDeleted">Show all</label>
+                <p-inputSwitch  *ngIf="mode=== bulkTypeApp"  id="showDeleted" (onChange)="refreshBulks()" [(ngModel)]="showDeleted" ngDefaultControl/>
+            </div>
             <div class="flex align-items-center mr-1">{{ 'BULK.LIST.PER_PAGE' | translate }}:</div>
             <span id="selectionItems" class="dropdown"
                   style="vertical-align: middle; display: inline-block; margin-right: 1rem;">
@@ -102,7 +135,7 @@
                 <li *ngIf="mode === bulkTypeApp && bulk?.state !== 'REMOVED'">
                     <a (click)="getAppBulkDetails(bulk?.id)"> {{"BULK.APP.DOWNLOAD_CSV" | translate}}</a>
                 </li>
-                <li *ngIf="mode === bulkTypeApp && bulk?.state !== 'REMOVED'">
+                <li *ngIf="mode === bulkTypeApp && !(bulk?.state === 'REMOVED' || bulk?.deleted )">
                     <a (click)="modal.show(); removeBulkId=bulk?.id">{{ 'BULK.LIST.REMOVE' | translate }}</a>
                 </li>
             </ul>
diff --git a/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.ts b/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.ts
index 6bc9e1ad97b4d5b90c287272922fbffc891a4615..4883a6bb95b8301576a8479a0d1aac8524bd0cb3 100644
--- a/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.ts
+++ b/src/app/appmarket/bulkDeployment/bulk-list/bulk-list.component.ts
@@ -1,17 +1,20 @@
-import {Component, Input, QueryList, ViewChild, ViewChildren} from '@angular/core';
+import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, QueryList, ViewChild, ViewChildren} from '@angular/core';
 import {BulkDeployment} from '../../../model/bulk-deployment';
 import {BulkType} from '../../../model/bulk-response';
 import {SortableHeaderDirective} from '../../../service/sort-domain.directive';
 import {ModalComponent} from '../../../shared';
 import {AppdeploymentService} from '../appdeployment.service';
 import {DomSanitizer} from '@angular/platform-browser';
+import { BulkQueueDetails } from '../../../model/bulk-queue-details';
+import { map, timer } from 'rxjs';
+import { ConfigurationService } from '../../../service';
 
 @Component({
     selector: 'app-bulk-list',
     templateUrl: './bulk-list.component.html',
     styleUrls: ['./bulk-list.component.css']
 })
-export class BulkListComponent {
+export class BulkListComponent implements OnDestroy, OnInit {
 
     public static BULK_ENTRY_DETAIL_KEY_APP_INSTANCE_NO = 'appInstanceNo';
     public static BULK_ENTRY_DETAIL_KEY_APP_INSTANCE_NAME = 'appName';
@@ -32,6 +35,10 @@ export class BulkListComponent {
     @ViewChild(ModalComponent, {static: true})
     public readonly modal: ModalComponent;
 
+    @Output()
+    public refresh: EventEmitter<boolean> = new EventEmitter<boolean>();
+
+    public showDeleted = false;
 
     public readonly bulkTypeDomain = BulkType.DOMAIN;
     public readonly bulkTypeApp = BulkType.APPLICATION;
@@ -44,8 +51,24 @@ export class BulkListComponent {
     public removeAll = false;
     public removeBulkId = 0;
 
+    public queueDetails : BulkQueueDetails;
+
+    public refreshQueue = undefined;
+    public sidebarVisible4 = false;
+
+    public configRefresh = 60;
+
+
     constructor(private appDeploy: AppdeploymentService,
-                private sanitizer: DomSanitizer) {
+                private sanitizer: DomSanitizer,
+                private configService: ConfigurationService) {   
+    }
+
+    public ngOnInit(): void {
+        this.configService.getConfiguration().subscribe(conf => {
+            this.configRefresh = conf.bulkDeploymentQueueRefresh;
+            this.update();
+        })
     }
 
     public getApplicationName(details: Map<string, string>) {
@@ -151,8 +174,41 @@ export class BulkListComponent {
 
     public removeBulk(): void {
         this.appDeploy.removeBulkDeployment(this.removeBulkId, this.removeAll).subscribe(_ => {
-            console.log("Bulk removed")
+            this.refreshBulks();
+            this.modal.hide();
         })
         this.removeAll = false;
     }
+
+    public refreshBulks(): void {
+        this.refresh.emit(this.showDeleted);
+    }
+
+    public getQueueDetails(): void {
+        this.appDeploy.getQueueDetails(0).subscribe(queue => {
+           console.log(queue);
+           this.queueDetails = queue;
+        })   
+    }
+
+     public update() {
+            this.refreshQueue = timer(0, this.refreshQueue * 1000).pipe(map(() => {
+              this.getQueueDetails();
+            })).subscribe()
+        }
+
+    public getQueryNumber() {
+        return this.queueDetails?.jobInQueue + this.queueDetails?.jobInProcess;
+    }
+
+        
+    public ngOnDestroy() {
+        if (this.refreshQueue !== undefined) {
+            this.refreshQueue.unsubscribe();
+        }
+    }
+
+    public open() {
+
+    }
 }
diff --git a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.css b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.css
index 415a4d52c3f56b52ae0540dc65b55bf5b1c3d599..66d99ef9dc8e1b044db0c92653980615c5db3ea5 100644
--- a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.css
+++ b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.css
@@ -34,4 +34,13 @@
     white-space: nowrap !important;
 }
 
+:host ::ng-deep .job-done-bar {
+    .p-progressbar-value {
+        border: 0 none;
+        margin: 0;
+        background:green;
+    }
+}
+    
+
 
diff --git a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.html b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.html
index c40a1ff6969dfe5322906d7e116981f228ef913a..9c870590051db4025f7b3d0dffbaeee499a71785 100644
--- a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.html
+++ b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.html
@@ -62,7 +62,7 @@
                             <td>{{getDomainId(response)}}</td>
                             <td>{{getDomainName(response)}}</td>
                             <td>{{getDomainCodeName(response)}}</td>
-                            <td style="width: 5%" class="text-right">
+                            <td style="width: 5%" class="text-right" *ngIf="bulk.state !== 'REMOVED'">
                                 <i *ngIf="response.type === 'DOMAIN'" class="pi pi-search" style="font-size: 1.8rem; cursor: pointer" [routerLink]="['/admin/domains/view/', response?.details['domainId']]"></i>
                                 <i *ngIf="response.type === 'USER'" class="pi pi-search" style="font-size: 1.8rem; cursor: pointer" [routerLink]="['/admin/users/view', response?.details['userId']]"></i>
                     <!-- <span class="dropdown">
@@ -160,6 +160,15 @@
             </div>
         </div>
 
+        <div class="" style="padding-bottom: 5rem;">
+            <label for="id" class="col-sm-2 control-label text-right mt-2">{{ 'BULK.LIST.APP_NAME' | translate }}</label>
+            <div class="col-sm-10">
+                <input type="text" class="form-control" id="id" name="id" [disabled]="true"
+                       [(ngModel)]="bulk.details['appName']" #name="ngModel">
+            </div>
+            
+        </div>
+
         <div class="" style="padding-bottom: 5rem">
             <label for="creator"
                    class="col-sm-2 control-label text-right mt-2">{{ 'BULK.LIST.CREATOR' | translate }}</label>
@@ -187,21 +196,31 @@
             </div>
         </div>
 
-        <div class="" style="padding-bottom: 5rem;">
-            <label for="id" class="col-sm-2 control-label text-right mt-2">{{ 'BULK.LIST.APP_NAME' | translate }}</label>
+        <div class="" style="padding-bottom: 5rem">
+            <label for="completionDate"
+                   class="col-sm-2 control-label text-right mt-2">{{ 'BULK.LIST.COMPLETION_DATE' | translate }}</label>
             <div class="col-sm-10">
-                <input type="text" class="form-control" id="id" name="id" [disabled]="true"
-                       [(ngModel)]="bulk.details['appName']" #name="ngModel">
+                <input type="text" class="form-control" id="completionDate" name="completionDate" [disabled]="true"
+                       placeholder="{{completionDate}}">
             </div>
-            
         </div>
 
-        <div class="flex justify-content-end" style="padding-right: 1.5rem">
+      
+
+        <div *ngIf="bulk.state !== 'REMOVED'" class="flex justify-content-end" style="padding-right: 1.5rem">
             <button class="btn btn-primary mr-2" (click)="refreshStates()">{{'BULK.APP.REFRESH' | translate}}</button>
 
-            <button class="btn btn-primary" (click)="getAppBulkDetails(this.bulkId)">{{'BULK.APP.DOWNLOAD_CSV' | translate}}</button>
+            <button *ngIf="bulk.state !== 'FAILED'" class="btn btn-primary" (click)="getAppBulkDetails(this.bulkId)">{{'BULK.APP.DOWNLOAD_CSV' | translate}}</button>
         </div>
-        <div class="panel panel-default" style="margin-top: 3rem">
+        <div class="mt-4">
+            <p-progressBar [mode]="progressBarMode"[value]="progressBarValue" id="progressBarr" [style]="{ height: '18px' }" [styleClass]="jobDone ? 'job-done-bar' : 'normal-bar'">
+                <ng-template pTemplate="content" let-value> 
+                    <span>{{queueDetails?.jobDone}} <span *ngIf="queueDetails?.jobDone !== bulk.entries.length">(+{{queueDetails?.jobInProcess}})</span> / {{bulk.entries.length}}</span>    
+                    </ng-template>
+            </p-progressBar>
+
+        </div>
+        <div class="panel panel-default" style="margin-top: 1rem">
             <div class="panel-heading">
 
                 <div style="display: flex; justify-content: start; align-items: center">
@@ -235,8 +254,8 @@
                             <td>{{getAppInstanceId(response)}}</td>
                             <td>{{getAppInstanceName(response)}}</td>
                             <td>{{getDomainCodeName(response)}}</td>
-                            <td style="width: 5%" class="text-right">
-                                <i class="pi pi-search" style="font-size: 1.8rem; cursor: pointer" [routerLink]="['/instances/', response?.details['appInstanceId']]"></i>
+                            <td style="width: 5%" class="text-right"  >
+                                <i *ngIf="response?.details['appInstanceId'] !== undefined" class="pi pi-search" style="font-size: 1.8rem; cursor: pointer" [routerLink]="['/instances/', response?.details['appInstanceId']]"></i>
                     <!-- <span *ngIf="response?.details['appInstanceId'] !== undefined" class="dropdown">
             <a  style="display: inline-block" class="dropdown-toggle " aria-expanded="false" aria-haspopup="true"
                data-toggle="dropdown" href="#" role="button">
diff --git a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.spec.ts b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.spec.ts
index 33287d7e82506504fe8fc2bf9a4100084a49ff39..2c9c55fa673bd9e1bafe4db2fc2e97d50359fd76 100644
--- a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.spec.ts
+++ b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.spec.ts
@@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { BulkViewComponent } from './bulk-view.component';
 import {HttpClientTestingModule} from '@angular/common/http/testing';
 import {RouterModule} from '@angular/router';
+import { DatePipe } from '@angular/common';
 
 describe('BulkViewComponent', () => {
   let component: BulkViewComponent;
@@ -14,6 +15,9 @@ describe('BulkViewComponent', () => {
       imports: [
           HttpClientTestingModule,
         RouterModule.forRoot([]),
+      ],
+      providers: [
+        DatePipe
       ]
     })
     .compileComponents();
diff --git a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.ts b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.ts
index 5895c0b6ba5531de6c627b1026c321333073a0df..4b0c59f9115bcae87a18f76b5ea7c109e3c5f9c9 100644
--- a/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.ts
+++ b/src/app/appmarket/bulkDeployment/bulk-view/bulk-view.component.ts
@@ -5,7 +5,9 @@ import {ActivatedRoute, Router} from '@angular/router';
 import {BulkResponse, BulkType} from '../../../model/bulk-response';
 import {timer} from 'rxjs';
 import {map} from 'rxjs/operators';
-import {AppImagesService} from '../../../service';
+import {AppImagesService, ConfigurationService} from '../../../service';
+import { BulkQueueDetails } from '../../../model/bulk-queue-details';
+import { DatePipe } from '@angular/common';
 
 @Component({
     selector: 'app-bulk-view',
@@ -20,21 +22,40 @@ export class BulkViewComponent implements OnInit, OnDestroy {
 
     public refresh = undefined;
 
+    public progressBarMode ;
+    public progressBarValue ;
+
+    public queueDetails :BulkQueueDetails; 
+
+    public jobDone = false;
+    public completionDate = "";
+
+    public configRefresh = 60;
+
     constructor(public deployService: AppdeploymentService,
                 private route: ActivatedRoute,
                 private router: Router,
                 public appImagesService: AppImagesService,
+                private datePipe: DatePipe,
+                private configService: ConfigurationService
     ) {
     }
 
     ngOnInit(): void {
+        this.configService.getConfiguration().subscribe(conf => {
+            this.configRefresh = conf.bulkDeploymentQueueRefresh;
+        })
+
         this.route.params.subscribe(params => {
             if (params['id'] !== undefined) {
                 this.bulkId = +params['id'];
                 this.deployService.getBulkDeployment(this.bulkId).subscribe(
                     (bulk) => {
                         this.bulk = bulk;
+                        this.sortByInstanceId();
                         this.bulkType = bulk.type;
+                        this.getQueueDetails();
+                        this.setCompletionDate(bulk);
                         if (this.bulkType === BulkType.APPLICATION) {
                             this.update();
                         }
@@ -88,10 +109,24 @@ export class BulkViewComponent implements OnInit, OnDestroy {
     }
 
     public update() {
-        this.refresh = timer(0, 20000).pipe(map(() => {
+        this.refresh = timer(0, this.configRefresh * 1000).pipe(map(() => {
             this.deployService.getBulkDeployment(this.bulk.id).subscribe(bulk => {
                 this.bulk = bulk;
+                this.sortByInstanceId();
+                this.setCompletionDate(bulk);
+                if(bulk.state === 'REMOVED') this.refresh.unsubscribe();
+                if(bulk.state === 'PROCESSING' && this.queueDetails.jobInProcessId === bulk.id) {
+                    this.progressBarMode = "determinate"
+                    this.setBarValue();
+                } else if(bulk.state === 'PROCESSING') {
+                    this.setBarValue();
+                    this.progressBarMode = "indeterminate"
+                } else {
+                    this.progressBarMode = "determinate"
+                    this.setBarValue();
+                }
             })
+           
         })).subscribe()
     }
 
@@ -103,7 +138,7 @@ export class BulkViewComponent implements OnInit, OnDestroy {
 
     public getAppBulkDetails(id: number) {
         this.deployService.getAppBulkDetails(id).subscribe( (data: Blob) => {
-            console.warn(data)
+            console.log(data)
             const blob = new Blob([data], { type: 'text/csv' });
             const url = window.URL.createObjectURL(blob);
             const a = document.createElement('a');
@@ -119,7 +154,43 @@ export class BulkViewComponent implements OnInit, OnDestroy {
     public refreshStates() {
         this.deployService.refreshStatesInBulkDeployment(this.bulkId).subscribe( deply => {
             this.bulk = deply;
-            console.log("Updated states of bulks")
+            this.sortByInstanceId();
+            this.setCompletionDate(deply);
+            this.getQueueDetails();
         })
     }
+
+    public setCompletionDate( deployment: BulkDeployment) {
+        if(this.bulk.completionDate !== undefined && this.bulk.completionDate !== null && deployment.state === 'COMPLETED') {
+            this.completionDate = this.datePipe.transform(this.bulk.completionDate,'dd-MM-yyyy HH:mm' )
+        } else {
+            this.completionDate = " - "
+        }
+    }
+
+    public setBarValue() {
+        this.getQueueDetails();
+    }
+    
+    public getQueueDetails(): void {
+     this.deployService.getQueueDetails(this.bulkId).subscribe(queue => {
+        this.queueDetails = queue;
+        if(queue.jobDone === this.bulk.entries.length) {
+            this.progressBarValue = 100;
+            this.jobDone = true;
+            this.progressBarMode = "determinate"
+        } else if(queue.jobDone === 0) {
+            this.progressBarMode = "indeterminate"
+        }else {
+            this.progressBarMode = "determinate"
+            this.progressBarValue =  queue.jobDone * 100 / this.bulk.entries.length;
+            this.jobDone = false;
+        }
+        
+     })   
+    }
+
+    public sortByInstanceId() {
+        this.bulk.entries.sort((a,b) => this.getAppInstanceId(a) < this.getAppInstanceId(b) ? 1 : -1);
+    }
 }
diff --git a/src/app/appmarket/domains/domain-group-view/domain-group-view.component.html b/src/app/appmarket/domains/domain-group-view/domain-group-view.component.html
index c42594752a704d430b01c6c597c099788a2ccb41..884fd53dc9108fdcc1b1e2a57db7b608a576f303 100644
--- a/src/app/appmarket/domains/domain-group-view/domain-group-view.component.html
+++ b/src/app/appmarket/domains/domain-group-view/domain-group-view.component.html
@@ -42,7 +42,7 @@
                 <div *roles="['ROLE_SYSTEM_ADMIN']" style="display: flex; justify-content: end">
                     <button  type="button" class="btn btn-secondary" (click)="showModalUser()">{{'DOMAINS.GROUP.ADD_USERS' | translate}}</button>
                 </div>
-                <div *roles="['ROLE_VL_MANAGER']" style="display: flex; justify-content: end">
+                <div *roles="['ROLE_GROUP_MANAGER']" style="display: flex; justify-content: end">
                     <button  type="button" class="btn btn-warning" (click)="removeMyAccess()">{{'DOMAINS.GROUP.DELETE_MYSELF' | translate}}</button>
                 </div>
                 <table class="table table-hover table-condensed" aria-describedby="Domains in Group table" style="margin-top: 2rem">
diff --git a/src/app/appmarket/domains/domain-groups/domain-groups.component.html b/src/app/appmarket/domains/domain-groups/domain-groups.component.html
index 53ae0e2083a29f2718b9b1cbd78c80e2039d1fe5..00e87a76702570d97b6ef962c5a6a0b83893f8b1 100644
--- a/src/app/appmarket/domains/domain-groups/domain-groups.component.html
+++ b/src/app/appmarket/domains/domain-groups/domain-groups.component.html
@@ -2,7 +2,7 @@
     <h3>{{'DOMAINS.LIST.GROUPS' | translate}}</h3>
     <div class="flex space-between">
         <div class="flex">
-            <a *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']" [routerLink]="['/admin/domains/groups/add']" class="btn btn-primary"
+            <a *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']" [routerLink]="['/admin/domains/groups/add']" class="btn btn-primary"
                role="button">{{'DOMAINS.ADD_BUTTON' | translate}}</a>
         </div>
         <div class="flex">
diff --git a/src/app/appmarket/domains/domains.routes.ts b/src/app/appmarket/domains/domains.routes.ts
index 12fb5a90bfaa0a6e3363b6e89855cebc7bbc4f9f..c99b22f037941a04df1c9e17f75d39a52ef6f085 100644
--- a/src/app/appmarket/domains/domains.routes.ts
+++ b/src/app/appmarket/domains/domains.routes.ts
@@ -13,7 +13,7 @@ import { DomainAnnotationsComponent } from './domain-annotations/domain-annotati
 export const DomainsRoutes: Route[] = [
     {
         path: 'admin/domains', component: DomainsListComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_DOMAIN_ADMIN', 'ROLE_OPERATOR', 'ROLE_VL_DOMAIN_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_DOMAIN_ADMIN', 'ROLE_OPERATOR', 'ROLE_GROUP_DOMAIN_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     {
         path: 'admin/domains/add', component: DomainComponent, canActivate: [AuthGuard, RoleGuard],
@@ -25,7 +25,7 @@ export const DomainsRoutes: Route[] = [
     },
     {
         path: 'admin/domains/view/:id', component: DomainComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_DOMAIN_ADMIN', 'ROLE_OPERATOR', 'ROLE_VL_DOMAIN_ADMIN']}
+        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_DOMAIN_ADMIN', 'ROLE_OPERATOR', 'ROLE_GROUP_DOMAIN_ADMIN']}
     },
     {
         path: 'admin/domains/edit/:id', component: DomainComponent, canActivate: [AuthGuard, RoleGuard],
@@ -33,25 +33,25 @@ export const DomainsRoutes: Route[] = [
     },
     {
         path: 'admin/domains/groups', component: DomainGroupsComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     {
         path: 'admin/domains/groups/add', component: DomainGroupViewComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {mode: ComponentMode.CREATE, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {mode: ComponentMode.CREATE, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     {
         path: 'admin/domains/groups/:id', component: DomainGroupViewComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     {
         path: 'admin/domains/bulks/new', component: DomainuploadComponent,
-        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}},
+        data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}},
     {
         path: 'admin/domains/bulks', component: BulkDomainListComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     },
     {
         path: 'admin/domains/bulks/:id', component: BulkViewComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']}
+        data: {roles: ['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']}
     }
 ];
diff --git a/src/app/appmarket/domains/list/domainslist.component.ts b/src/app/appmarket/domains/list/domainslist.component.ts
index de210023a06690a4cff6b3001fff0c4f714fea93..b6256b314fd0729197b3c9cf8861033cd4ff4bd0 100644
--- a/src/app/appmarket/domains/list/domainslist.component.ts
+++ b/src/app/appmarket/domains/list/domainslist.component.ts
@@ -62,7 +62,7 @@ export class DomainsListComponent implements OnInit {
                 map((domains) => domains.filter((domain) => domain.id !== this.domainService.getGlobalDomainId())));
         } else {
             return this.domainService.getMyDomains().pipe(
-                map((domains) => domains.filter((domain) => this.authService.hasDomainRole(domain.id, Role[Role.ROLE_DOMAIN_ADMIN]) || this.authService.hasDomainRole(domain.id, Role[Role.ROLE_VL_DOMAIN_ADMIN]))));
+                map((domains) => domains.filter((domain) => this.authService.hasDomainRole(domain.id, Role[Role.ROLE_DOMAIN_ADMIN]) || this.authService.hasDomainRole(domain.id, Role[Role.ROLE_GROUP_DOMAIN_ADMIN]))));
         }
     }
 
diff --git a/src/app/appmarket/users/list/userslist.component.html b/src/app/appmarket/users/list/userslist.component.html
index 6d9333ad9f77cb06d0cc389dc13401150af6c16e..76236c39205a2e4fe779f033f276151a3b12b0e8 100644
--- a/src/app/appmarket/users/list/userslist.component.html
+++ b/src/app/appmarket/users/list/userslist.component.html
@@ -11,7 +11,7 @@
 </div>
 
 <div class="col-sm-12" *ngIf="domainMode">
-	<div *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_VL_MANAGER']">
+	<div *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_GROUP_MANAGER']">
 		<nmaas-userslist *ngIf="!isInAddToDomainMode" [users]="allUsers" [allowedModes]="[ComponentMode.VIEW, ComponentMode.DELETE]" [domainMode]="true" (onUserRoleChange)="onUserRoleChange($event)"
 						 (onView)="onUserView($event)" (onModeChange)="onModeChange($event)" (onDelete)="onUserDelete($event)" (onRemoveFromDomain)="onRemoveRole($event)">
 		</nmaas-userslist>
diff --git a/src/app/appmarket/users/list/userslist.component.ts b/src/app/appmarket/users/list/userslist.component.ts
index 3bb01ecd9dd280bf7bfc623d7a34e26f2d3e1727..dbcbc5545d6dd437cc30d86fa55c74823a1e8807 100644
--- a/src/app/appmarket/users/list/userslist.component.ts
+++ b/src/app/appmarket/users/list/userslist.component.ts
@@ -57,7 +57,7 @@ export class UsersListComponent implements OnInit {
             users = this.userService.getDomainUsersAsAdmin(this.domainId);
         } else if (this.authService.hasRole(Role[Role.ROLE_SYSTEM_ADMIN])) {
             users = this.userService.getAll(this.domainId);
-        } else if (this.domainId != null && (this.authService.hasDomainRole(this.domainId, Role[Role.ROLE_DOMAIN_ADMIN]) || this.authService.hasDomainRole(this.domainId, Role[Role.ROLE_VL_DOMAIN_ADMIN]))) {
+        } else if (this.domainId != null && (this.authService.hasDomainRole(this.domainId, Role[Role.ROLE_DOMAIN_ADMIN]) || this.authService.hasDomainRole(this.domainId, Role[Role.ROLE_GROUP_DOMAIN_ADMIN]))) {
             this.domainMode = true;
             users = this.userService.getAll(this.domainId);
         } else {
diff --git a/src/app/appmarket/users/userdetails/userdetails.component.html b/src/app/appmarket/users/userdetails/userdetails.component.html
index 6baf5888a19174411af0589f1fcfed73cbcb78e1..f728a79ce158c48bcbe6db89c05d4452d03a47c3 100644
--- a/src/app/appmarket/users/userdetails/userdetails.component.html
+++ b/src/app/appmarket/users/userdetails/userdetails.component.html
@@ -7,5 +7,6 @@
 	<div>
 	<nmaas-userdetails [user]="user" [(userDetailsMode)]="userDetailsMode" [allowedModes]="[ComponentMode.VIEW, ComponentMode.EDIT]" [(errorMessage)]="errorMessage" (onSave)="onSave($event)" (refresh)="onRefresh()"></nmaas-userdetails>
 	<nmaas-userprivileges [allowedModes]="[ComponentMode.VIEW, ComponentMode.CREATE]" [user]="user"></nmaas-userprivileges>
+	<nmaas-ssh-keys *roles="['ROLE_SYSTEM_ADMIN']" [userMode]="true" [userId]="user?.id"></nmaas-ssh-keys>
 	</div>
 </div>
diff --git a/src/app/appmarket/users/users.routes.ts b/src/app/appmarket/users/users.routes.ts
index abe74e43673b587888d86cf984e1d54252e1e2fa..82be539df3e5deed04c5375cb9d52fabc5602bc8 100644
--- a/src/app/appmarket/users/users.routes.ts
+++ b/src/app/appmarket/users/users.routes.ts
@@ -10,5 +10,5 @@ export const UsersRoutes: Route[] = [
     { path: 'admin/users/view/:id', component: UserDetailsComponent, canActivate: [AuthGuard, RoleGuard],
                       data: {mode: ComponentMode.VIEW, roles: ['ROLE_SYSTEM_ADMIN']} },
     { path: 'domain/users', component: UsersListComponent, canActivate: [AuthGuard, RoleGuard],
-        data: {roles: ['ROLE_DOMAIN_ADMIN', 'ROLE_VL_MANAGER', 'ROLE_VL_MANAGER']}},
+        data: {roles: ['ROLE_DOMAIN_ADMIN', 'ROLE_GROUP_MANAGER', 'ROLE_GROUP_MANAGER']}},
 ];
diff --git a/src/app/auth/auth.guard.ts b/src/app/auth/auth.guard.ts
index aea400e0a3ccf6885624238b496fcbd5186d9e2e..a0578db6eb36a04c7c1458465f54678545a43810 100644
--- a/src/app/auth/auth.guard.ts
+++ b/src/app/auth/auth.guard.ts
@@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
 import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
 import {AuthService} from './auth.service';
 import {ConfigurationService} from '../service';
+import { debounceTime } from 'rxjs';
 
 @Injectable()
 export class AuthGuard  {
@@ -11,13 +12,7 @@ export class AuthGuard  {
 
   public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
     if (this.auth.isLogged()) {
-      this.maintenanceService.getConfiguration().subscribe(value => {
-         if (!this.auth.hasRole('ROLE_SYSTEM_ADMIN') && value.maintenance) {
-             this.auth.logout();
-             this.router.navigate(['/welcome/login']);
-             return false;
-         }
-      });
+    
       if(this.auth.hasRole('ROLE_INCOMPLETE') && route.url.toString() !== 'complete') {
           this.router.navigate(['/complete']);
           return false;
diff --git a/src/app/auth/auth.service.spec.ts b/src/app/auth/auth.service.spec.ts
index 6b0bb367feea3e0729c83c0209409e8d8d32dace..170ece28132bc78a75fd54ad8338c48914b82ea4 100644
--- a/src/app/auth/auth.service.spec.ts
+++ b/src/app/auth/auth.service.spec.ts
@@ -1,16 +1,20 @@
 /* tslint:disable:no-unused-variable */
-import { TestBed, waitForAsync } from '@angular/core/testing';
+import {TestBed, waitForAsync} from '@angular/core/testing';
 import {AuthService} from './auth.service';
-import {AppConfigService} from '../service';
+import {AppConfigService, ConfigurationService} from '../service';
 import {JwtHelperService} from '@auth0/angular-jwt';
-import {HttpClientTestingModule} from '@angular/common/http/testing';
-import {Role} from '../model/userrole';
+import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
+import {Role, UserRole} from '../model/userrole';
+import {ProfileService} from '../service/profile.service';
+import {Observable, of} from 'rxjs';
+import {Configuration} from '../model/configuration';
 
 describe('Service: Auth', () => {
     let authService: AuthService;
     let appConfigServiceSpy: jasmine.SpyObj<AppConfigService>;
     let jwtHelperServiceSpy: jasmine.SpyObj<JwtHelperService>;
-
+    let maintenanceServiceSpy: jasmine.SpyObj<ConfigurationService>;
+    let httpMock: HttpTestingController;
     let store: any = {};
 
     beforeEach(waitForAsync(() => {
@@ -18,34 +22,74 @@ describe('Service: Auth', () => {
             config: {
                 apiUrl: 'http://api.url',
                 tokenName: 'token',
-            }
+            },
+            getTestInstanceModalKey: () => 'testModalKey'
         };
-
         const jwtSpy = jasmine.createSpyObj('JwtHelperService', ['decodeToken', 'isTokenExpired']);
         jwtSpy.decodeToken.and.returnValue({
             language: 'pl',
             sub: 'test-user',
-            scopes: [{authority: '1:' + Role[Role.ROLE_SYSTEM_ADMIN]}, {authority: '2:' + Role[Role.ROLE_USER]}]
+            global_role: ['ROLE_SYSTEM_ADMIN'],
+            roles: [`ROLE_USER`]
         });
         jwtSpy.isTokenExpired.and.callFake((arg: string): boolean => {
             return arg !== 'valid';
         });
 
+        maintenanceServiceSpy = jasmine.createSpyObj('maintenanceService', ['getConfiguration']);
+        maintenanceServiceSpy.getConfiguration.and.returnValue(of())
+
+        class MockConfigurationService {
+            protected uri: string;
+
+            constructor() {
+                this.uri = 'http://localhost/api';
+            }
+
+            public getApiUrl(): string {
+                return 'http://localhost/api';
+            }
+
+            public getConfiguration(): Observable<Configuration> {
+                return of<Configuration>();
+            }
+
+            public updateConfiguration(configuration: Configuration): Observable<any> {
+                return of<Configuration>();
+            }
+        }
+
+
+        const userRole = new UserRole();
+        userRole.role = Role.ROLE_SYSTEM_ADMIN;
+        userRole.domainName = 'test';
+        userRole.domainId = 1;
+        const userRole2 = new UserRole();
+        userRole2.role = Role.ROLE_USER;
+        userRole2.domainName = 'test2';
+        userRole2.domainId = 2;
+        const profileServiceStub = jasmine.createSpyObj('ProfileService', ['getRoles']);
+        profileServiceStub.getRoles.and.returnValue(of([userRole, userRole2]))
+
         TestBed.configureTestingModule({
             imports: [
-                HttpClientTestingModule
+                HttpClientTestingModule,
             ],
             providers: [
                 AuthService,
                 {provide: AppConfigService, useValue: appConfigServiceStub},
                 {provide: JwtHelperService, useValue: jwtSpy},
+                {provide: ProfileService, useValue: profileServiceStub},
+                {provide: ConfigurationService, useClass: MockConfigurationService}
             ],
         });
 
+        httpMock = TestBed.inject(HttpTestingController)
         authService = TestBed.get(AuthService);
+        authService.profile = [userRole, userRole2]
         appConfigServiceSpy = TestBed.get(AppConfigService);
         jwtHelperServiceSpy = TestBed.get(JwtHelperService);
-        // spyOn(appConfigServiceSpy, 'getTestInstanceModalKey').and.returnValue("test-instance-modal-key");
+        // maintenanceServiceSpy = TestBed.get(ConfigurationService);
 
         // local store mock
         store = {token: 'valid'};
@@ -61,6 +105,10 @@ describe('Service: Auth', () => {
         });
 
     }));
+    afterEach(() => {
+        httpMock.verify();
+        store = {};
+    });
 
     it('should create service', () => {
         expect(authService).toBeTruthy();
@@ -99,7 +147,7 @@ describe('Service: Auth', () => {
     });
 
     it('should return domains from roles', () => {
-        const result  = authService.getDomains();
+        const result = authService.getDomains();
         expect(result).toContain(1);
         expect(result).toContain(2);
         store = {token: null};
@@ -137,8 +185,11 @@ describe('Service: Auth', () => {
     });
 
     it('should remove token on logout', () => {
+        store['oidc-token'] = 'some-oidc-token';
         authService.logout();
         expect(store['token']).not.toBeDefined();
+        const req = httpMock.expectOne('http://api.url/oidc/logout/some-oidc-token');
+        req.flush({});
     });
 
     it('should be logged in when token is present and valid', () => {
@@ -154,4 +205,58 @@ describe('Service: Auth', () => {
         expect(r).toEqual(false);
     });
 
+    it('should store token and oidc token in localStorage', () => {
+        authService.storeToken('abc123');
+        expect(store['token']).toEqual('abc123');
+
+        authService.storeOidcToken('oidc456');
+        expect(store['oidc-token']).toEqual('oidc456');
+    });
+
+    it('should remove roles from localStorage', () => {
+        store['rolesToken'] = 'some_roles';
+        authService.removeRoles();
+        expect(store['rolesToken']).toBeUndefined();
+    });
+
+    it('should load and parse roles from localStorage', () => {
+        const roles = [{domainId: 1, role: Role.ROLE_USER, domainName: 'x'}];
+        store['rolesToken'] = JSON.stringify(roles);
+
+        const result = authService.loadRoles();
+        expect(result.length).toEqual(1);
+        expect(result[0].role).toEqual(Role.ROLE_USER);
+    });
+
+    it('should assign loaded roles to profile', () => {
+        const roles = [{domainId: 2, role: Role.ROLE_DOMAIN_ADMIN, domainName: 'x'}];
+        store['rolesToken'] = JSON.stringify(roles);
+        authService.loadAndSaveRoles();
+        expect(authService.profile[0].role).toEqual(Role.ROLE_DOMAIN_ADMIN);
+    });
+    it('should stringify and store roles', () => {
+        const roles = [new UserRole()];
+        roles[0].domainId = 1;
+        roles[0].role = Role.ROLE_USER;
+        roles[0].domainName = 'dom1';
+
+        authService.storeRoles(roles);
+        expect(store['rolesToken']).toContain('ROLE_USER');
+    });
+    it('should get global role from token', () => {
+        const result = authService.getGlobalRole();
+        expect(result).toContain('ROLE_SYSTEM_ADMIN');
+    });
+
+    it('should handle login error with catchError', waitForAsync(() => {
+        authService.login('user', 'pass').subscribe({
+            next: () => fail('Expected error'),
+            error: (err) => {
+                expect(err.status).toEqual(401);
+            }
+        });
+
+        const req = httpMock.expectOne('http://api.url/auth/basic/login');
+        req.flush({ message: 'Invalid credentials' }, { status: 401, statusText: 'Unauthorized' });
+    }));
 });
diff --git a/src/app/auth/auth.service.ts b/src/app/auth/auth.service.ts
index ca9cd4baf71a4e61c5ebc46832ca7e0d4d821875..6156c8e479cfd788ed7808556017f30cb57bc40f 100644
--- a/src/app/auth/auth.service.ts
+++ b/src/app/auth/auth.service.ts
@@ -1,17 +1,18 @@
-import {BehaviorSubject, Observable, Subject, throwError as observableThrowError} from 'rxjs';
+import {BehaviorSubject, Observable, of, Subject, throwError as observableThrowError} from 'rxjs';
 import {catchError, debounceTime, map} from 'rxjs/operators';
 import {Injectable} from '@angular/core';
-import {AppConfigService} from '../service';
+import {AppConfigService, ConfigurationService} from '../service';
 import {JwtHelperService} from '@auth0/angular-jwt';
 import {HttpClient, HttpHeaders} from '@angular/common/http';
-import {Authority} from '../model';
+import {ProfileService} from '../service/profile.service';
+import {Role, UserRole} from '../model/userrole';
 
-export class DomainRoles {
-    constructor(private domainId: number, private roles: string[] = []) {
-    }
 
-    public getDomainId(): number {
-        return this.domainId;
+export class DomainRoles {
+    constructor(
+        private domainId: number,
+        private roles: string[] = []
+    ) {
     }
 
     public getRoles(): string[] {
@@ -28,25 +29,101 @@ export class AuthService {
     public loginUsingSsoService: boolean;
 
     private readonly isLoggedInSubject: Subject<boolean> = new BehaviorSubject<boolean>(false);
+    public profile: UserRole[]
+
+    private rolesTabelName = 'rolesToken'
+
+    private refresh: any;
+
+    private maintenance: boolean = false;
 
 
     constructor(private http: HttpClient,
                 private appConfig: AppConfigService,
-                private jwtHelper: JwtHelperService) {
+                private jwtHelper: JwtHelperService,
+                private profileService: ProfileService,
+                private maintenanceService: ConfigurationService) {
+        this.loadAndSaveRoles();
+        this.loadUser()
+        this.getConfigurationToCheckMaintenance();
+    }
+
+    public loadUser(): void {
+
+        this.profileService.getRoles().subscribe(roles => {
+            this.profile = roles
+            this.storeRoles(roles)
+        })
+    }
+
+    public refreshUserRoles(): void {
+        this.refresh = setInterval(() => {
+            if (this.isLogged()) {
+                this.loadUser();
+            }
+        }, 60000);
+    }
+
+    private getConfigurationToCheckMaintenance() {
+        this.maintenanceService.getConfiguration().subscribe(value => {
+            if (value !== undefined && value !== null && value.maintenance) {
+                console.warn('Maintenance is on. Disabled login.')
+                this.isLoggedInSubject.next(false);
+                this.logout();
+                this.maintenance = true;
+                return false;
+            }
+        });
     }
+
     //TODO make this static again and serive this feature in other way
     public storeToken(token: string): void {
         localStorage.setItem(this.appConfig.config.tokenName, token);
     }
 
+    public storeRoles(roles: UserRole[]): void {
+        const rolesString = JSON.stringify(roles);
+        localStorage.setItem(this.rolesTabelName, rolesString);
+    }
+
+    public loadAndSaveRoles() {
+        this.profile = this.loadRoles();
+    }
+
+    public loadRoles(): UserRole[] {
+        const rolesString = localStorage.getItem(this.rolesTabelName);
+        if (!rolesString) {
+            return null;
+        }
+
+        const parsed = JSON.parse(rolesString);
+        return parsed.map((item: any) => Object.assign(new UserRole(), item));
+    }
+
+    public removeRoles(): void {
+        localStorage.removeItem(this.rolesTabelName)
+    }
+
+    public storeOidcToken(token: string): void {
+        localStorage.setItem('oidc-token', token);
+    }
+
     private getToken(): string {
         return localStorage.getItem(this.appConfig.config.tokenName)
     }
 
+    private getOidcToken(): string {
+        return localStorage.getItem('oidc-token')
+    }
+
     private removeToken(): void {
         localStorage.removeItem(this.appConfig.config.tokenName);
     }
 
+    private removeOidcToken(): void {
+        localStorage.removeItem('oidc-token');
+    }
+
     public getSelectedLanguage(): string {
         if (localStorage.getItem('lang') != null) {
             return localStorage.getItem('lang')
@@ -59,62 +136,60 @@ export class AuthService {
         return (token ? this.jwtHelper.decodeToken(token).sub : null);
     }
 
-    public hasRole(name: string): boolean {
+    public getPreferredUsername(): string {
         const token = this.getToken();
-        const authorities: Authority[] = this.jwtHelper.decodeToken(token).scopes;
-        for (let i = 0; i < authorities.length; i++) {
-            if (authorities[i].authority.indexOf(name) > -1) {
+        return (token ? this.jwtHelper.decodeToken(token).preferred_username : null);
+    }
+
+    public hasRole(name: string): boolean {
+
+        const roles = this.getRoles()
+
+        for (const role of roles) {
+            if (role === name) {
                 return true;
             }
         }
         return false;
+
     }
 
     public hasDomainRole(domainId: number, name: string): boolean {
-        const token = this.getToken();
-        const authorities: Authority[] = this.jwtHelper.decodeToken(token).scopes;
-        for (let i = 0; i < authorities.length; i++) {
-            if (authorities[i].authority.indexOf(domainId + ':' + name) > -1) {
-                return true;
+        let result = false;
+        const domainRoles: Map<number, DomainRoles> = this.getDomainRoles();
+        for (const [mapDomainId, domainRolesValue] of domainRoles) {
+            if (mapDomainId === domainId) {
+                domainRolesValue.getRoles().forEach(role => {
+                    if (role === name) {
+                        result = true;
+                    }
+                })
             }
         }
-        return false;
+        return result;
     }
 
-    public getDomainRoles(): Map<number, DomainRoles> {
-        const drMap: Map<number, DomainRoles> = new Map<number, DomainRoles>();
-
+    public getGlobalRole(): string[] {
         const token = this.getToken();
         if (token == null) {
-            return drMap;
+            return null;
         }
+        return this.jwtHelper.decodeToken(token).global_role;
+    }
 
-        const authorities: Authority[] = this.jwtHelper.decodeToken(token).scopes;
-        if (authorities == null) {
-            return drMap;
-        }
+    public getDomainRoles(): Map<number, DomainRoles> {
+        const domainRolesMap: Map<number, DomainRoles> = new Map<number, DomainRoles>();
 
-        for (let index = 0; index < authorities.length; index++) {
-            if (authorities[index].authority === undefined) {
-                continue;
-            }
+        const domains: number[] = this.getDomains();
+        for (const domain of domains) {
+            const roles: string[] = this.profile
+                .filter(userRole => userRole.domainId === domain)
+                .map(userRole => Role[userRole.role])
 
-            const domainRole: string[] = authorities[index].authority.split(':', 2);
-            if (domainRole.length !== 2) {
-                continue;
-            }
-            const domainId: number = Number.parseInt(domainRole[0], 10);
-            const role: string = domainRole[1];
+            domainRolesMap.set(domain, new DomainRoles(domain, roles));
 
-            let dr: DomainRoles;
-            if (!drMap.has(domainId)) {
-                drMap.set(domainId, new DomainRoles(domainId, []));
-            }
-            dr = drMap.get(domainId);
-            dr.getRoles().push(role);
         }
-
-        return drMap;
+        return domainRolesMap;
     }
 
     public getRoles(): string[] {
@@ -124,56 +199,35 @@ export class AuthService {
         if (token == null) {
             return roles;
         }
+        const domainRoles: string[] = this.jwtHelper.decodeToken(token).roles;
+        const globalRole: string[] = this.jwtHelper.decodeToken(token).global_role;
 
-        const authorities: Authority[] = this.jwtHelper.decodeToken(token).scopes;
-        for (let index = 0; index < authorities.length; index++) {
-            if (authorities[index].authority === undefined) {
-                continue;
-            }
+        roles.push(globalRole[0]);
 
-            const domainRole: string[] = authorities[index].authority.split(':', 2);
-            if (domainRole.length !== 2) {
-                continue;
-            }
-            const role: string = domainRole[1];
-            if (roles.indexOf(role) === -1) {
-                roles.push(role);
-            }
+        for (const role of domainRoles) {
+
+            roles.push(role);
         }
+
         return roles;
     }
 
 
     public getDomains(): number[] {
-        const domains: number[] = [];
-
-        const token = this.getToken();
-        if (token == null) {
-            return domains;
-        }
-
-        const authorities: Authority[] = this.jwtHelper.decodeToken(token).scopes;
-
-        for (let index = 0; index < authorities.length; index++) {
-            if (authorities[index].authority === undefined) {
-                continue;
+        if (this.isLogged()) {
+            if (this.profile !== undefined && this.profile !== null) {
+                return this.getDomainIds();
+            } else {
+                return [];
             }
 
-            const domainIdStr: string[] = authorities[index].authority.split(':', 1);
-            if (domainIdStr.length === 0) {
-                continue;
-            }
-            const domainId: number = Number.parseInt(domainIdStr[0], 10);
-            if (domains.indexOf(domainId) === -1) {
-                domains.push(domainId);
-            }
         }
-        return domains;
+        return [];
+
     }
 
     public getDomainsWithRole(name: string): number[] {
         const domainsWithRole: number[] = [];
-
         const domains: number[] = this.getDomains();
         domains.forEach((domainId) => {
             if (this.hasDomainRole(domainId, name)) {
@@ -184,10 +238,60 @@ export class AuthService {
         return domainsWithRole;
     }
 
+    public oidcLinkingLogin(oidcToken: string,
+                            email: string,
+                            password: string,
+                            uuid: string,
+                            firstName: string,
+                            lastName: string) {
+        const headers = new HttpHeaders({'Content-Type': 'application/json', 'Accept': 'application/json'});
+
+        return this.http.post(this.appConfig.config.apiUrl + '/oidc/link',
+            JSON.stringify(
+                {
+                    'oidcToken': oidcToken,
+                    'email': email,
+                    'password': password,
+                    'uuid': uuid,
+                    'firstName': firstName,
+                    'lastName': lastName,
+                }
+            ),
+            {headers: headers}).pipe(
+            debounceTime(1000),
+            map((res: Response) => {
+                    const token = res && res['token'];
+                    const oidcToken = res && res['oidcToken'];
+                    if (token && oidcToken) {
+                        this.storeToken(token);
+                        this.storeOidcToken(oidcToken);
+                        this.loginUsingSsoService = false;
+                        this.isLoggedInSubject.next(true);
+                        this.profileService.getRoles().subscribe(profile => {
+                            this.profile = profile
+                            this.storeRoles(profile);
+                            return true;
+                        })
+                    } else {
+                        this.isLoggedInSubject.next(false);
+                        return false;
+                    }
+                }
+            ),
+        )
+    }
+
     public login(username: string, password: string): Observable<boolean> {
         // hack so test instance modal is shown onl after login
         localStorage.setItem(this.appConfig.getTestInstanceModalKey(), 'True');
 
+        if (this.maintenance) {
+            this.isLoggedInSubject.next(false);
+            console.warn('Maintenance is on. Disabled login.')
+            //add toast here 
+            return of(false);
+        }
+
         const headers = new HttpHeaders({'Content-Type': 'application/json', 'Accept': 'application/json'});
         return this.http.post(this.appConfig.config.apiUrl + '/auth/basic/login',
             JSON.stringify({'username': username, 'password': password}), {headers: headers}).pipe(
@@ -206,7 +310,11 @@ export class AuthService {
                     console.debug('AUTH | DomainRoles: ' + this.getDomainRoles());
                     this.loginUsingSsoService = false;
                     this.isLoggedInSubject.next(true);
-                    return true;
+                    this.profileService.getRoles().subscribe(profile => {
+                        this.profile = profile
+                        this.storeRoles(profile);
+                        return true;
+                    })
                 } else {
                     // return false to indicate failed login
                     this.isLoggedInSubject.next(false);
@@ -226,48 +334,26 @@ export class AuthService {
             }));
     }
 
-    public propagateSSOLogin(userid: string): Observable<boolean> {
-        console.debug('propagateSSOLogin');
-        console.debug('propagateSSOLogin ' + this.appConfig.config.apiUrl);
-        console.debug('propagateSSOLogin ' + this.appConfig.config.apiUrl + '/auth/sso/login');
-        console.debug('propagateSSOLogin ' + userid);
-        // hack so test instance modal is shown onl after login
-        localStorage.setItem(this.appConfig.getTestInstanceModalKey(), 'True');
-
-        const headers = new HttpHeaders({'Content-Type': 'application/json', 'Accept': 'application/json'});
-        return this.http.post(this.appConfig.config.apiUrl + '/auth/sso/login',
-            JSON.stringify({'userid': userid}), {headers: headers}).pipe(
-            debounceTime(10000),
-            map((response: Response) => {
-                console.debug('SSO login response: ' + response);
-                // login successful if there's a jwt token in the response
-                const token = response && response['token'];
-
-                if (token) {
-                    this.storeToken(token);
-                    console.debug('SSO AUTH | User: ' + this.getUsername());
-                    console.debug('SSO AUTH | Domains: ' + this.getDomains());
-                    console.debug('SSO AUTH | Roles: ' + this.getRoles());
-                    console.debug('SSO AUTH | DomainRoles: ' + this.getDomainRoles());
-                    this.loginUsingSsoService = true;
-                    this.isLoggedInSubject.next(true);
-                    return true;
-                } else {
-                    // return false to indicate failed login
-                    this.isLoggedInSubject.next(false);
-                    return false;
-                }
-            }),
-            catchError((error) => {
-                console.error('SSO login error: ' + error.error['message']);
-                return observableThrowError(error);
-            }));
+    public logout(): void {
+        const oidcToken = this.getOidcToken();
+        this.refresh = null;
+        if (oidcToken === null) {
+            this.removeToken();
+            this.isLoggedInSubject.next(false);
+            localStorage.removeItem('_expiredTime');
+        } else {
+            this.removeToken();
+            this.removeOidcToken();
+            this.isLoggedInSubject.next(false);
+            localStorage.removeItem('_expiredTime');
+            this.http.get(this.appConfig.config.apiUrl + '/oidc/logout/' + oidcToken).subscribe(() => {
+            })
+        }
     }
 
-    public logout(): void {
-        this.removeToken();
-        this.isLoggedInSubject.next(false);
-        localStorage.removeItem('_expiredTime');
+    public oidcLogout(oidcToken: string): void {
+        this.http.get(this.appConfig.config.apiUrl + '/oidc/logout/' + oidcToken).subscribe(() => {
+        })
     }
 
     public isLogged(): boolean {
@@ -278,10 +364,9 @@ export class AuthService {
         return (token ? !this.jwtHelper.isTokenExpired(token) : false);
     }
 
-    get isLoggedIn$(): Observable<boolean> {
-        return this.isLoggedInSubject.pipe(
-            debounceTime(100), // use debounceTime to aggregate multiple emissions https://rxjs.dev/api/operators/debounceTime
-        );
+
+    public getDomainIds(): number[] {
+        return Array.from(new Set(this.profile.map(ur => ur.domainId)));
     }
 
 }
diff --git a/src/app/auth/login-success/login-success.component.ts b/src/app/auth/login-success/login-success.component.ts
index d84fe015ab346f24da5bd1a2e1743b6ade19eca9..e7fec74d4dcaa6d40ec0da867a432314d09eb307 100644
--- a/src/app/auth/login-success/login-success.component.ts
+++ b/src/app/auth/login-success/login-success.component.ts
@@ -1,5 +1,5 @@
 import {Component, OnInit} from '@angular/core';
-import {ActivatedRoute} from '@angular/router';
+import {ActivatedRoute, Router} from '@angular/router';
 import {AuthService} from '../auth.service';
 
 @Component({
@@ -8,19 +8,25 @@ import {AuthService} from '../auth.service';
     styleUrls: ['./login-success.component.css']
 })
 export class LoginSuccessComponent implements OnInit {
-    constructor(private route: ActivatedRoute,
-                private authService: AuthService) {
+    constructor(private readonly router: Router,
+                private readonly route: ActivatedRoute,
+                private readonly authService: AuthService) {
     }
 
 
     ngOnInit(): void {
-        // Pobieranie tokena z parametrów URL
         this.route.queryParams.subscribe(params => {
             const token = params['token'];
             const refreshToken = params['refresh_token'];
+            const oidcToken = params['oidc_token'];
             if (token) {
                 this.authService.storeToken(token);
             }
-        });
+            if (refreshToken) {
+                this.authService.storeOidcToken(oidcToken);
+            }
+            this.router.navigate(['/'])
+        })
+
     }
 }
diff --git a/src/app/model/bulk-deployment.ts b/src/app/model/bulk-deployment.ts
index bf8828bb54fb0fa2dfdbfb0ad7cfc50f725979c9..1af669ecbe0bd3e05068993accf1dd17854d90e4 100644
--- a/src/app/model/bulk-deployment.ts
+++ b/src/app/model/bulk-deployment.ts
@@ -10,6 +10,8 @@ export class BulkDeployment {
     public type: BulkType;
     public details: Map<string, string>;
     public parallelDeploymentsLimit: number;
+    public deleted: boolean;
+    public completionDate: Date;
 }
 
 export enum BulkDeploymentState {
diff --git a/src/app/model/bulk-queue-details.ts b/src/app/model/bulk-queue-details.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a86da4af02b6c0151783ddbe7733b54db57d5877
--- /dev/null
+++ b/src/app/model/bulk-queue-details.ts
@@ -0,0 +1,8 @@
+export class BulkQueueDetails {
+
+    public jobInProcess: number;
+    public jobInProcessId: number;
+    public jobInQueue: number;
+    public jobDone: number;
+    public bulkJobInQueue: number;
+}
\ No newline at end of file
diff --git a/src/app/model/configuration.ts b/src/app/model/configuration.ts
index 3bffd6e8f90421fa78c8e722ece5d6de9b8aeb2d..40896c07bfc2b1439633aef88f05cb1660beceec 100644
--- a/src/app/model/configuration.ts
+++ b/src/app/model/configuration.ts
@@ -11,4 +11,7 @@ export class Configuration {
     public appInstanceFailureEmailList: string[] = [];
     public bulkDeploymentJobCron: string;
     public parallelDeploymentsLimit: number;
+    public bulkDeploymentQueueRefresh: number;
+    public deploymentPrefix: string;
+    public bulkDeploymentTimeThreshold: number;
 }
diff --git a/src/app/model/userrole.ts b/src/app/model/userrole.ts
index ee06e84b3828a14565b91448cae2c595b73fda3a..acf7ac2f0228e50b8220b4e1812e47fd4377a473 100644
--- a/src/app/model/userrole.ts
+++ b/src/app/model/userrole.ts
@@ -1,14 +1,14 @@
 export enum Role {
-  ROLE_SYSTEM_ADMIN,
-  ROLE_DOMAIN_ADMIN,
-  ROLE_OPERATOR,
-  ROLE_TOOL_MANAGER,
-  ROLE_USER,
-  ROLE_GUEST,
-  ROLE_INCOMPLETE,
-  ROLE_NOT_ACCEPTED,
-  ROLE_VL_MANAGER,
-  ROLE_VL_DOMAIN_ADMIN
+  ROLE_SYSTEM_ADMIN = 'ROLE_SYSTEM_ADMIN',
+  ROLE_DOMAIN_ADMIN = 'ROLE_DOMAIN_ADMIN',
+  ROLE_OPERATOR = "ROLE_OPERATOR",
+  ROLE_TOOL_MANAGER = "ROLE_TOOL_MANAGER",
+  ROLE_USER = "ROLE_USER",
+  ROLE_GUEST = "ROLE_GUEST",
+  ROLE_INCOMPLETE = "ROLE_INCOMPLETE",
+  ROLE_NOT_ACCEPTED = "ROLE_NOT_ACCEPTED",
+  ROLE_GROUP_MANAGER = "ROLE_GROUP_MANAGER",
+  ROLE_GROUP_DOMAIN_ADMIN = "ROLE_GROUP_DOMAIN_ADMIN",
 }
 
 export function RoleAware(constructor: Function) {
diff --git a/src/app/service/appconfig.service.ts b/src/app/service/appconfig.service.ts
index c9988bcc13d5245f923bc152e29f7618cc774ac7..df61388c90ac79ee006e8922fb695a032bae7ed8 100644
--- a/src/app/service/appconfig.service.ts
+++ b/src/app/service/appconfig.service.ts
@@ -25,10 +25,7 @@ export class AppConfigService {
     }
 
     public getOidcUrl(): string {
-        if (this.config == null) {
-            return 'http://localhost:9000/oauth2/authorization/my-oidc';
-        }
-        return this.config.oidcUrl;
+        return this.config.apiUrl + '/oauth2/authorization/my-oidc';
     }
 
     public getApiUrl(): string {
@@ -67,6 +64,7 @@ export class AppConfigService {
     }
 
     public getSiteKey(): string {
+        console.log("Site key:", this.config.captchaKey)
         if (this.config == null) {
             return '';
         }
diff --git a/src/app/service/cluster.service.ts b/src/app/service/cluster.service.ts
index dace40815e83787a5897843b9d7206c153ca2686..4830699766480719290f664be76a554b8c85725d 100644
--- a/src/app/service/cluster.service.ts
+++ b/src/app/service/cluster.service.ts
@@ -17,22 +17,11 @@ export class ClusterService extends GenericDataService {
     constructor(http: HttpClient, appConfig: AppConfigService) {
         super(http, appConfig);
 
-        this.url = this.appConfig.getApiUrl() + '/management/kubernetes/';
+        this.url = this.appConfig.getApiUrl() + '/management/kubernetes';
     }
 
     public getCluster(): Observable<Cluster> {
         return this.get<Cluster>(this.url);
     }
 
-    public add(cluster: Cluster): Observable<any> {
-        return this.post(this.url, cluster);
-    }
-
-    public update(cluster: Cluster): Observable<any> {
-        return this.put(this.url + cluster.id, cluster);
-    }
-
-    public remove(clusterId: number): Observable<any> {
-        return this.http.delete(this.url + clusterId);
-    }
 }
diff --git a/src/app/service/configuration.service.ts b/src/app/service/configuration.service.ts
index 9a247125cd18b4bd8f7cb2bb0e74e19cc9e62d10..9d93b4018f6ead3cfc3eb71c3db60417323b71bd 100644
--- a/src/app/service/configuration.service.ts
+++ b/src/app/service/configuration.service.ts
@@ -22,7 +22,7 @@ export class ConfigurationService extends GenericDataService{
   }
 
   public updateConfiguration(configuration: Configuration): Observable<any>{
-    return this.put(this.uri + configuration.id, configuration);
+    return this.put(this.uri + "/"+ configuration.id, configuration);
   }
 
 }
diff --git a/src/app/service/domain.service.ts b/src/app/service/domain.service.ts
index ead7327158be7cadb18056da214ba9224f67a410..7ed0257a4aca76390edd525a84274cb6667c150d 100644
--- a/src/app/service/domain.service.ts
+++ b/src/app/service/domain.service.ts
@@ -117,7 +117,7 @@ export class DomainService extends GenericDataService {
   }
 
   public updateDomainGroupManagers(managers: User[], id: number): Observable<DomainGroup> {
-    return this.put(this.url + 'group/members/' + id, managers);
+    return this.put(this.url + '/group/members/' + id, managers);
   }
 
   public getAnnotations(): Observable<DomainAnnotation[]> {
diff --git a/src/app/service/profile.service.ts b/src/app/service/profile.service.ts
index 0c745763a950266d06cfa37e2f574eeb336a2cc8..ee77d26c2101c874456c1d6ebd1e868aa0cc68d7 100644
--- a/src/app/service/profile.service.ts
+++ b/src/app/service/profile.service.ts
@@ -4,6 +4,7 @@ import {AppConfigService} from './appconfig.service';
 import {Observable} from 'rxjs';
 import {User} from '../model';
 import {HttpClient} from '@angular/common/http';
+import { UserRole } from '../model/userrole';
 
 
 @Injectable({
@@ -19,6 +20,10 @@ export class ProfileService extends GenericDataService {
     return this.http.get<User>(this.getProfileUrl() + 'user')
   }
 
+  public getRoles(): Observable<UserRole[]> {
+    return this.http.get<UserRole[]>(this.getProfileUrl() + 'user/roles')
+  }
+
   protected getProfileUrl(): string {
       return this.appConfig.getApiUrl() + '/profile/'
   }
diff --git a/src/app/service/shell-client.service.ts b/src/app/service/shell-client.service.ts
index 7a1cb49aef95fb181afe999a4bfaa17bc8599141..7d920a07bae5f470a5fc97ea19b286993a4b1ecf 100644
--- a/src/app/service/shell-client.service.ts
+++ b/src/app/service/shell-client.service.ts
@@ -18,11 +18,11 @@ export class ShellClientService {
 
     public initConnection(id: number, pod: string): Observable<string> {
         // @ts-ignore
-        return this.http.post<string>(this.appConfig.getApiUrl() + '/shell/' + id + '/init/' + pod, {}, {responseType: 'text'});
+        return this.http.post<string>(this.appConfig.getApiUrl() + '/pods/shell/' + id + '/init/' + pod, {}, {responseType: 'text'});
     }
 
     public sendCommand(sessionId: string, command: Object = {}): Observable<any> {
-        return this.http.post(this.appConfig.getApiUrl() + '/shell/' + sessionId + '/command', command);
+        return this.http.post(this.appConfig.getApiUrl() + '/pods/shell/' + sessionId + '/command', command);
     }
 
     /**
@@ -30,7 +30,7 @@ export class ShellClientService {
      */
     public closeConnection(sessionId: string) {
         this.closeEventStream()
-        this.http.delete(this.appConfig.getApiUrl() + '/shell/' + sessionId).subscribe(
+        this.http.delete(this.appConfig.getApiUrl() + '/pods/shell/' + sessionId).subscribe(
             () => console.log('session completed: ', sessionId),
             error => console.error('error completing session', error))
     }
@@ -42,7 +42,7 @@ export class ShellClientService {
 
     public getServerSentEvent(sessionId: string): Observable<OnMessageEvent> {
         return new Observable<OnMessageEvent>(observableEvents => {
-            const events = this._sseService.getEventSource(this.appConfig.getApiUrl() + '/shell/' + sessionId);
+            const events = this._sseService.getEventSource(this.appConfig.getApiUrl() + '/pods/shell/' + sessionId);
 
             events.onopen = onopenEvent => {
                 this._zone.run(() => {
@@ -67,7 +67,7 @@ export class ShellClientService {
     }
 
     public getPossiblePods(id: number): Observable<PodInfo[]> {
-        return this.http.get<PodInfo[]>(this.appConfig.getApiUrl() + '/shell/' + id + '/podnames');
+        return this.http.get<PodInfo[]>(this.appConfig.getApiUrl() + '/pods/shell/' + id + '/podnames');
     }
 
 }
diff --git a/src/app/service/sshkey.service.ts b/src/app/service/sshkey.service.ts
index f6b47b7245f782a9190f9bae5b6d1347cd398bdf..32424f472417e56ad29d71c83ff42cb5959f862b 100644
--- a/src/app/service/sshkey.service.ts
+++ b/src/app/service/sshkey.service.ts
@@ -26,4 +26,17 @@ export class SSHKeyService extends GenericDataService {
   public invalidate(id: number): Observable<any> {
     return this.delete(this.appConfig.getApiUrl() + '/user/keys/' + id);
   }
+
+  public getAllByUserId(userId: number): Observable<SSHKeyView[]> {
+    return this.get<SSHKeyView[]>(this.appConfig.getApiUrl() + '/user/keys/view/' + userId);
+  }
+
+  public createKeyForUser(request: SSHKeyRequest, userId: number ): Observable<any> {
+    return this.put<SSHKeyRequest, any>(this.appConfig.getApiUrl() + '/user/keys/view/' + userId, request);
+  }
+
+  public invalidateUserKey(keyId: number, userId: number): Observable<any> {
+    return this.delete(this.appConfig.getApiUrl() + '/user/keys/view/' + userId + "/" + keyId);
+  }
+
 }
diff --git a/src/app/service/sso.service.spec.ts b/src/app/service/sso.service.spec.ts
deleted file mode 100644
index 447e1159701776ff09a20d63fefdee219f341f06..0000000000000000000000000000000000000000
--- a/src/app/service/sso.service.spec.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { TestBed, inject } from '@angular/core/testing';
-
-import { SSOService } from './sso.service';
-import {Observable, of} from 'rxjs';
-import {Configuration} from '../model/configuration';
-import {HttpClient, HttpHandler} from '@angular/common/http';
-import {AppConfigService} from './appconfig.service';
-
-class MockConfigurationService {
-    protected uri: string;
-
-    constructor() {
-        this.uri = 'http://localhost/api';
-    }
-
-    public getApiUrl(): string {
-        return 'http://localhost/api';
-    }
-
-    public getConfiguration(): Observable<Configuration> {
-        return of<Configuration>();
-    }
-
-    public updateConfiguration(configuration: Configuration): Observable<any> {
-        return of<Configuration>();
-    }
-}
-
-describe('SSOService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [SSOService, HttpHandler, HttpClient, {provide: AppConfigService, useClass: MockConfigurationService}]
-    });
-  });
-
-  it('should be created', inject([SSOService], (service: SSOService) => {
-    expect(service).toBeTruthy();
-  }));
-});
diff --git a/src/app/service/sso.service.ts b/src/app/service/sso.service.ts
deleted file mode 100644
index c3ff73bfa55445414fc44f6c923af9607c6dc61b..0000000000000000000000000000000000000000
--- a/src/app/service/sso.service.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Injectable } from '@angular/core';
-import {GenericDataService} from './genericdata.service';
-import {HttpClient} from '@angular/common/http';
-import {AppConfigService} from './appconfig.service';
-import {Observable} from 'rxjs';
-import {SSOConfig} from '../model/sso';
-
-@Injectable()
-export class SSOService extends GenericDataService {
-
-  protected url: string;
-
-  constructor(http: HttpClient, appConfig: AppConfigService) {
-    super(http, appConfig);
-    this.url = this.appConfig.getApiUrl() + '/auth/sso';
-  }
-
-  public getOne(): Observable<SSOConfig> {
-    return this.get<SSOConfig>(this.url);
-  }
-
-}
diff --git a/src/app/service/user.service.ts b/src/app/service/user.service.ts
index bfdf43c7362644120cee3c2a4ac7dfac4e6c3494..8393eb431889e4f88d5c70304a12104b3a1634d7 100644
--- a/src/app/service/user.service.ts
+++ b/src/app/service/user.service.ts
@@ -20,19 +20,19 @@ export class UserService extends GenericDataService {
 
     public getAll(domainId?: number): Observable<User[]> {
         return this.get<User[]>(domainId === undefined || domainId === this.domainService.getGlobalDomainId() ?
-            this.getUsersUrl() : this.getDomainUsersUrl(domainId));
+            this.getUsersUrlWithoutDash() : this.getDomainUsersUrlWithoutDash(domainId));
     }
 
     public getOne(userId: number, domainId?: number): Observable<User> {
-        return this.get<User>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + '/'  + userId);
+        return this.get<User>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + userId);
     }
 
     public deleteOne(userId: number, domainId?: number): Observable<any> {
-        return this.delete<any>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + '/'  + userId);
+        return this.delete<any>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + userId);
     }
 
     public getRoles(userId: number, domainId?: number): Observable<UserRole[]> {
-        return this.get<UserRole[]>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + '/'  + userId + '/roles');
+        return this.get<UserRole[]>((domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId))  + userId + '/roles');
     }
 
     public updateUser(userId: number, user: User): Observable<any> {
@@ -53,7 +53,7 @@ export class UserService extends GenericDataService {
     }
 
     public addRole(userId: number, role: Role, domainId?: number): Observable<any> {
-        const url: string = (domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + '/' + userId + '/roles';
+        const url: string = (domainId === undefined ? this.getUsersUrl() : this.getDomainUsersUrl(domainId)) + userId + '/roles';
         const targetDomainId: number = (domainId === undefined ? this.appConfig.getNmaasGlobalDomainId() : domainId);
 
         return this.post<UserRole, UserRole>(url, new UserRole(targetDomainId, undefined, role));
@@ -87,7 +87,16 @@ export class UserService extends GenericDataService {
         return this.appConfig.getApiUrl() + '/users/';
     }
 
+    protected getUsersUrlWithoutDash(): string {
+        return this.appConfig.getApiUrl() + '/users';
+    }
+
+
     protected getDomainUsersUrl(domainId: number): string {
+        return this.appConfig.getApiUrl() + '/domains/' + domainId + '/users/';
+    }
+
+    protected getDomainUsersUrlWithoutDash(domainId: number): string {
         return this.appConfig.getApiUrl() + '/domains/' + domainId + '/users';
     }
 
@@ -96,7 +105,7 @@ export class UserService extends GenericDataService {
     }
 
     protected getUserAcceptanceUrl(): string {
-        return this.appConfig.getApiUrl() + '/users/terms/';
+        return this.appConfig.getApiUrl() + '/users/terms';
     }
 
     protected getEnableOrDisableUsersUrl(userId: number, enabled: boolean): string {
diff --git a/src/app/shared/about/about.component.css b/src/app/shared/about/about.component.css
index cbf25d83e53161e2bfe9524f48abbe82c72e31e3..4a9f3de4150444470b0d301c1752aa16ef708229 100644
--- a/src/app/shared/about/about.component.css
+++ b/src/app/shared/about/about.component.css
@@ -16,3 +16,11 @@
     padding-left: 15px;
     padding-right:15px;
 }
+.position{
+    display: flex;
+}
+@media (max-width: 991px){
+    .position{
+        flex-direction: column-reverse;
+    }
+}
diff --git a/src/app/shared/about/about.component.html b/src/app/shared/about/about.component.html
index 624cbd8f01ae0b577f99c2acbb0643eb82124ec8..df6d0eb479e590e7436abc90906638ecbe4fb3d0 100644
--- a/src/app/shared/about/about.component.html
+++ b/src/app/shared/about/about.component.html
@@ -1,4 +1,4 @@
-<div class="col-md-offset-1 col-md-10 col-lg-offset-1 col-lg-10 row" style="padding-bottom: 80px; padding-top: 80px;">
+<div class="col-md-offset-1 col-md-10 col-lg-offset-1 col-lg-10 row position" style="padding-bottom: 80px; padding-top: 80px;">
     <div class="col-md-6">
         <div class="" style="padding-bottom: 15px;">
             <h2>{{ 'ABOUT.CHANGELOG_TITLE' | translate }}</h2>
@@ -41,16 +41,16 @@
     <div class="col-md-6">
         <div class="" style="padding-bottom: 15px;">
             <h2>{{ 'ABOUT.CONTACT_TITLE' | translate }}</h2>
-            <span>{{ 'ABOUT.CONTACT_DESC' | translate}}</span>
-            <p>Join the mailing list: </p>
+            <p>Join the mailing list of your interest: </p>
             <ul>
                 <li>
-                    <p><a href="https://lists.geant.org/sympa/info/nmaas-announce">low frequency nmaas news</a> - Mailing list for nmaas-related announcements sent out by the nmaas Team members</p>
+                    <p><a href="https://lists.geant.org/sympa/info/nmaas-announce">nmaas-announce</a> - for nmaas-related announcements sent out by the nmaas Team members,</p>
                 </li>
                 <li>
-                    <p><a href="https://lists.geant.org/sympa/info/nmaas-users ">users discussion about nmaas</a> -  Mailing list for message exchange between nmaas users and the nmaas Team</p>
+                    <p><a href="https://lists.geant.org/sympa/info/nmaas-users">nmaas-users</a> - for discussions and message exchange between nmaas users and the nmaas Team.</p>
                 </li>
             </ul>
+            <span>{{ 'ABOUT.CONTACT_DESC' | translate}}</span>
         </div>
         <div class="panel panel-default">
             <div class="panel-body">
diff --git a/src/app/shared/common/domainfilter/domainfilter.component.ts b/src/app/shared/common/domainfilter/domainfilter.component.ts
index bbef4bda7a01842696ec6d3ac4369463704dfd5e..48472f0247fb83250824874f96a70d87648e2385 100644
--- a/src/app/shared/common/domainfilter/domainfilter.component.ts
+++ b/src/app/shared/common/domainfilter/domainfilter.component.ts
@@ -106,6 +106,7 @@ export class DomainFilterComponent implements OnInit {
 
     private sortDomains(): void {
         const globalDomainId = this.domainService.getGlobalDomainId();
+        console.log(this.domains);
         this.domains = this.domains.pipe(
             map(
                 domains => {
@@ -123,10 +124,13 @@ export class DomainFilterComponent implements OnInit {
                         domains.unshift(defaultDomain)
                     }
                     this.domainsLocal = domains;
+                    this.filteredDomainsSub.next(this.domainsLocal);
                     return domains
                 }
             )
         )
+        console.log(this.domainsLocal);
+        
     }
 
     public changeDomain(domainId: number, domainName: string) {
diff --git a/src/app/shared/contact/contact.component.ts b/src/app/shared/contact/contact.component.ts
index 732955b972b12bf62d045cb8aa57edfbc34ba737..2ccb5d3e20301d266483167f47290518c7b79a2b 100644
--- a/src/app/shared/contact/contact.component.ts
+++ b/src/app/shared/contact/contact.component.ts
@@ -125,8 +125,11 @@ export class ContactComponent implements OnInit {
     private sendMail(data: any): Observable<void> {
         // submit captcha request
         return this.recaptchaV3Service.execute('contactForm').pipe(
-            catchError(_ => of('')), // in case of captcha error return empty token
+            catchError(error => {
+                console.error(error);
+                return of(error)}), // in case of captcha error return empty token
             map((token) => {
+                console.log(token)
                 const result = {token, mail: new Mail()} // create mail object
                 result.mail.otherAttributes = data; // set properties and mail attributes
                 result.mail.otherAttributes.subType = this.formType.key;
diff --git a/src/app/shared/footer/footer.component.html b/src/app/shared/footer/footer.component.html
index bbce48b72740f03e6b38520708430af57b838036..58f81ac5538eeb5823019387969a37198e0e38e4 100644
--- a/src/app/shared/footer/footer.component.html
+++ b/src/app/shared/footer/footer.component.html
@@ -4,7 +4,7 @@
 			<div class="col-sm-2">
 				<!-- nmaas Logo optionally -->
                 <a href="https://www.geant.org/">
-                    <img alt="Geant Logo" src="/assets/images/geant-logo.png"  width="200" class="image-link"/>
+                    <img alt="GÉANT Logo" src="/assets/images/geant-logo.png"  width="200" class="image-link"/>
                 </a>
 			</div>
             <div class="col-sm-3">
diff --git a/src/app/shared/navbar/navbar.component.css b/src/app/shared/navbar/navbar.component.css
index 5978cfb11627290845a547fca380052b4cb72606..55bdd7192499c31c22991e19beac919fb0bbf82d 100644
--- a/src/app/shared/navbar/navbar.component.css
+++ b/src/app/shared/navbar/navbar.component.css
@@ -26,11 +26,6 @@
 .lang-circle-icon{
   height: 26px;
 }
-.navbar-left{
-  padding-top: 6px;
-  display: flex;
-  align-items: center;
-}
 .navbar-right{
   display:flex;
   align-items: center;
@@ -48,7 +43,6 @@
   }
   .navbar-left,.navbar-right {
     float: none !important;
-    display:block;
   }
   .navbar-toggle {
     display: block;
@@ -203,18 +197,16 @@
   color: #414F6B;
 }
 .navbar-default .navbar-nav>li>a{
-  color: #414F6B;
-  padding:10px;
+  color: #6D788E;
 }
 .navbar-default .navbar-nav>.active>a{
   border-radius: 5px;
   color: #142548;
- padding:10px;
+  /*font-weight: bold;*/
   background-color: #D1D1D1;
 }
 .navbar-default .navbar-nav>.open>a{
   border-radius: 5px;
   color: #142548;
-  padding:10px;
   background-color: #D1D1D1;
 }
diff --git a/src/app/shared/navbar/navbar.component.html b/src/app/shared/navbar/navbar.component.html
index b75127c4b75f76f275941006c1910aa93457bac3..cead22d4afd206aea61c47f15b9c44bff96b8767 100644
--- a/src/app/shared/navbar/navbar.component.html
+++ b/src/app/shared/navbar/navbar.component.html
@@ -1,7 +1,8 @@
 <nav class="navbar navbar-default" id="navbar" role="navigation" style="margin:0">
     <div class="container-fluid">
         <div class="navbar-header">
-            <a routerLink="/"><img alt="Geant" src="assets/images/logo-small.png" style="margin: 8px; padding:4px; height:35px"></a>
+            <a routerLink="/"><img alt="GÉANT" src="assets/images/logo-small.png"
+                                   style="margin: 8px; padding:4px; height:35px"></a>
             <button class="navbar-toggle" data-target="#navbarCollapse" data-toggle="collapse" type="button">
                 <span class="sr-only">Toggle Navigation</span>
                 <em class="fas fa-bars"></em>
@@ -20,22 +21,22 @@
             </ul>
             <ul *ngIf="authService.isLogged()" class="nav navbar-nav navbar-right">
                 <li *ngIf="showClock" class="">
-                    <div class="navbar-logout">{{'NAVBAR.EXPIRED_TIME' | translate}}: {{time}}</div>
+                    <div class="navbar-logout">{{ 'NAVBAR.EXPIRED_TIME' | translate }}: {{ time }}</div>
                 </li>
                 <li *ngIf="showClock" class="divider-vertical"></li>
                 <li *ngIf="checkUserRole()" class="drop-domain">
                     <nmaas-domain-filter class="drop-domain"></nmaas-domain-filter>
                 </li>
-                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']" class="divider-vertical"></li>
-                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']" [routerLinkActiveOptions]="{exact:true}"
+                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']" class="divider-vertical"></li>
+                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']" [routerLinkActiveOptions]="{exact:true}"
                     [routerLinkActive]="['active']" class="dropdown">
                     <a aria-expanded="false" aria-haspopup="true" class="dropdown-toggle" data-toggle="dropdown"
-                       role="button">{{'NAVBAR.ADVANCED' | translate}}<strong class="caret"></strong></a>
+                       role="button">{{ 'NAVBAR.ADVANCED' | translate }}<strong class="caret"></strong></a>
                     <ul class="dropdown-menu">
-                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']">
+                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']">
                             <a [routerLink]="['/admin/domains/bulks']">{{ 'BULK.DOMAIN.HEADER' | translate }}</a>
                         </li>
-                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']">
+                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']">
                             <a [routerLink]="['/admin/apps/bulks']">{{ 'BULK.APP.HEADER' | translate }}</a>
                         </li>
                     </ul>
@@ -44,15 +45,15 @@
                 <li *roles="['ROLE_SYSTEM_ADMIN']" [routerLinkActiveOptions]="{exact:true}"
                     [routerLinkActive]="['active']" class="dropdown">
                     <a aria-expanded="false" aria-haspopup="true" class="dropdown-toggle" data-toggle="dropdown"
-                       role="button">{{'NAVBAR.NOTIFICATION' | translate}}<strong class="caret"></strong></a>
+                       role="button">{{ 'NAVBAR.NOTIFICATION' | translate }}<strong class="caret"></strong></a>
                     <ul class="dropdown-menu">
                         <li *roles="['ROLE_SYSTEM_ADMIN']">
-                            <span (click)="showNotificationModal()">{{'NAVBAR.ALL_USERS' | translate}}</span>
+                            <span (click)="showNotificationModal()">{{ 'NAVBAR.ALL_USERS' | translate }}</span>
                         </li>
                     </ul>
                 </li>
                 <li *roles="['ROLE_SYSTEM_ADMIN']" class="divider-vertical"></li>
-                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_OPERATOR', 'ROLE_DOMAIN_ADMIN', 'ROLE_TOOL_MANAGER', 'ROLE_VL_MANAGER']"
+                <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_OPERATOR', 'ROLE_DOMAIN_ADMIN', 'ROLE_TOOL_MANAGER', 'ROLE_GROUP_MANAGER']"
                     [routerLinkActiveOptions]="{exact:true}"
                     [routerLinkActive]="['active']" class="dropdown">
                     <a aria-expanded="false" aria-haspopup="true" class="dropdown-toggle" data-toggle="dropdown"
@@ -66,20 +67,21 @@
                         <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_TOOL_MANAGER']"><a
                                 [routerLink]="['/admin/apps']">{{ 'NAVBAR.MARKET' | translate }}</a>
                         </li>
-                        <li *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_SYSTEM_ADMIN', 'ROLE_OPERATOR', 'ROLE_VL_MANAGER', 'ROLE_VL_DOMAIN_ADMIN']"><a
-                                [routerLink]="['/admin/domains']">{{ 'NAVBAR.DOMAINS' | translate }}</a>
+                        <li *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_SYSTEM_ADMIN', 'ROLE_OPERATOR', 'ROLE_GROUP_MANAGER', 'ROLE_GROUP_DOMAIN_ADMIN']">
+                            <a
+                                    [routerLink]="['/admin/domains']">{{ 'NAVBAR.DOMAINS' | translate }}</a>
                         </li>
-                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_VL_MANAGER']">
+                        <li *roles="['ROLE_SYSTEM_ADMIN', 'ROLE_GROUP_MANAGER']">
                             <a [routerLink]="['/admin/domains/groups']">{{ 'NAVBAR.DOMAIN_GROUPS' | translate }}</a>
                         </li>
                         <li *roles="['ROLE_SYSTEM_ADMIN']"><a
                                 [routerLink]="['/admin/users']">{{ 'NAVBAR.USERS' | translate }}</a>
                         </li>
-                        <li *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_VL_DOMAIN_ADMIN']"><a
+                        <li *roles="['ROLE_DOMAIN_ADMIN', 'ROLE_GROUP_DOMAIN_ADMIN']"><a
                                 [routerLink]="['/domain/users']">{{ 'NAVBAR.DOMAIN_USERS' | translate }}</a>
                         </li>
                         <li *roles="['ROLE_SYSTEM_ADMIN']"><a
-                                [routerLink]="['/admin/languages']">{{'NAVBAR.LANGUAGES' | translate }}</a>
+                                [routerLink]="['/admin/languages']">{{ 'NAVBAR.LANGUAGES' | translate }}</a>
                         </li>
 
                         <li *roles="['ROLE_SYSTEM_ADMIN']" class="dropdown-divider"></li>
@@ -94,7 +96,7 @@
                     <a aria-expanded="false" aria-haspopup="true" class="dropdown-toggle"
                        data-toggle="dropdown" href="#" role="button">
                         <span class="glyphicon glyphicon-user"></span>
-                        {{authService.getUsername()}} <strong class="caret"></strong></a>
+                        {{ authService.getPreferredUsername() }} <strong class="caret"></strong></a>
                     <ul class="dropdown-menu">
                         <li [routerLinkActiveOptions]="{exact:true}" [routerLinkActive]="['active']"><a
                                 [routerLink]="['/profile']">{{ 'NAVBAR.PROFILE' | translate }}</a></li>
@@ -108,12 +110,16 @@
 
             <ul *ngIf="!authService.isLogged()" class="nav navbar-nav pull-right-lg" id="navbar-main-not-logged">
                 <li>
-                    <button *ngIf="router.url == '/welcome' || router.url.startsWith('/welcome/login') || router.url == '/welcome/registration'" data-parent="#accordion"
-                            class="btn navbar-btn accordion-group" data-target="#login-panel" data-toggle="collapse" [routerLink]="['welcome/login']">
+                    <button *ngIf="router.url == '/welcome' || router.url.startsWith('/welcome/login') || router.url == '/welcome/registration'"
+                            data-parent="#accordion"
+                            class="btn navbar-btn accordion-group" data-target="#login-panel" data-toggle="collapse"
+                            [routerLink]="['welcome/login']">
                         {{ 'WELCOME.LOGIN' | translate }}
                     </button>
-                    <button *ngIf="router.url == '/welcome' || router.url.startsWith('/welcome/login') || router.url == '/welcome/registration'" data-parent="#accordion"
-                            class="btn navbar-btn accordion-group" data-target="#register-panel" data-toggle="collapse" [routerLink]="['welcome/registration']">
+                    <button *ngIf="router.url == '/welcome' || router.url.startsWith('/welcome/login') || router.url == '/welcome/registration'"
+                            data-parent="#accordion"
+                            class="btn navbar-btn accordion-group" data-target="#register-panel" data-toggle="collapse"
+                            [routerLink]="['welcome/registration']">
                         {{ 'WELCOME.REGISTER' | translate }}
                     </button>
                 </li>
@@ -136,7 +142,7 @@
                             <a (click)="useLanguage(lang)">
                                 <img alt="lang flag" class="lang-circle-icon"
                                      src="assets/images/country/{{lang}}_circle.png"/>
-                                <span>{{lang.toUpperCase()}}</span>
+                                <span>{{ lang.toUpperCase() }}</span>
                             </a>
                         </li>
                     </ul>
diff --git a/src/app/shared/navbar/navbar.component.spec.ts b/src/app/shared/navbar/navbar.component.spec.ts
index 7f81b7e65f719b681db4b423c85550e84c0a7e0d..fe0dc2256e63c906623f7fd69c28c13ff2513064 100644
--- a/src/app/shared/navbar/navbar.component.spec.ts
+++ b/src/app/shared/navbar/navbar.component.spec.ts
@@ -49,11 +49,12 @@ describe('NavbarComponent_Shared', () => {
         const mockLanguageService = jasmine.createSpyObj(['getEnabledLanguages', 'shouldUpdate']);
         mockLanguageService.getEnabledLanguages.and.returnValue(of(['en', 'fr', 'pl']));
         mockLanguageService.shouldUpdate.and.returnValue(false);
-        const mockAuthService = jasmine.createSpyObj(['isLogged', 'hasRole', 'getDomains', 'getRoles']);
+        const mockAuthService = jasmine.createSpyObj(['isLogged', 'hasRole', 'getDomains', 'getRoles', 'loadUser', 'refreshUserRoles']);
         mockAuthService.isLogged.and.returnValue(false);
         mockAuthService.hasRole.and.returnValue(false);
         mockAuthService.getDomains.and.returnValue([]);
         mockAuthService.getRoles.and.returnValue([]);
+        mockAuthService.refreshUserRoles.and.returnValue();
         const mockUserDataService = jasmine.createSpyObj(['selectedDomainId'])
         mockUserDataService.selectedDomainId.and.returnValue(1)
 
diff --git a/src/app/shared/navbar/navbar.component.ts b/src/app/shared/navbar/navbar.component.ts
index 394fcdfe84fa6c6fb988684ebc71df8b9a90ff0e..ee1d343013ae4f642475899fd2a5d4d329e45d19 100644
--- a/src/app/shared/navbar/navbar.component.ts
+++ b/src/app/shared/navbar/navbar.component.ts
@@ -56,15 +56,15 @@ export class NavbarComponent implements OnInit {
     ngOnInit() {
         this.isServiceAvailable = this.serviceAvailability.isServiceAvailable;
         this.getSupportedLanguages();
+        this.authService.refreshUserRoles();
         if (this.authService.isLogged()) {
-            if (this.authService.hasRole('ROLE_SYSTEM_ADMIN')) {
                 this.refresh = interval(5000).subscribe(next => {
                     if (this.languageService.shouldUpdate()) {
                         this.getSupportedLanguages();
                         this.languageService.setUpdateRequiredFlag(false);
                     }
                 });
-            }
+            // }
         }
         this.intervalId = setInterval(() => {
             if (this.authService.isLogged()) {
@@ -88,10 +88,12 @@ export class NavbarComponent implements OnInit {
     }
 
     public checkUserRole(): boolean {
-        return this.authService.getDomains().filter(value => value !== this.domainService.getGlobalDomainId()).length > 0
+        if (this.authService.isLogged()) {
+            return this.authService.getDomains().filter(value => value !== this.domainService.getGlobalDomainId()).length > 0
             || this.authService.getRoles().filter(value => value !== 'ROLE_INCOMPLETE')
                 .filter(value => value !== 'ROLE_GUEST')
                 .length > 0;
+        }
     }
 
     public showNotificationModal(): void {
@@ -99,7 +101,7 @@ export class NavbarComponent implements OnInit {
     }
 
     public isOnlyGuestInGlobalDomain(): boolean {
-        const globalDomainRoles = this.authService.getDomainRoles().get(this.domainService.getGlobalDomainId()).getRoles()
+        const globalDomainRoles = this.authService.getGlobalRole()
         return globalDomainRoles  // does have any role in global domain (not undefined)
             && globalDomainRoles.length === 1  // only one role in global domain
             && globalDomainRoles[0] === 'ROLE_GUEST'  // this single role is ROLE_GUEST
diff --git a/src/app/shared/page-not-found/page-not-found.component.css b/src/app/shared/page-not-found/page-not-found.component.css
index 81255a0b4ffd0b6f3f6e72de771581796a4648da..d1bc030c6435a8816481bec18f3bc499207c5439 100644
--- a/src/app/shared/page-not-found/page-not-found.component.css
+++ b/src/app/shared/page-not-found/page-not-found.component.css
@@ -1,5 +1,5 @@
 .container-fluid {
-    min-height: 100vh;
+    min-height: 55vh;
     padding: 25px;
     background-repeat: no-repeat;
     background-color: rgb(255, 255, 255);
diff --git a/src/app/shared/page-not-found/page-not-found.component.html b/src/app/shared/page-not-found/page-not-found.component.html
index 64b11d2695c7b7e0c9db9c59d82fe8b5b026bc11..48dfe9e1d3a6916e20f9c7da4f431064c0012576 100644
--- a/src/app/shared/page-not-found/page-not-found.component.html
+++ b/src/app/shared/page-not-found/page-not-found.component.html
@@ -3,7 +3,7 @@
     <img src="assets/images/error/404.gif" width="60%">
   </div>
   <div class="row">
-    <h1>Oops! Something went wrong.</h1>
+    <h1>Oops! Something went wrong (404).</h1>
     <p>Our robot couldn't find this page. Try a different link or head back to the homepage.</p>
     <button class="btn btn-primary" type="button" (click)="redirect()">Go back</button>
   </div>
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 2eb8101c668d54d301660d87298f6adc819d93e8..a6243e0198db0195b3b444eb4e99116ce403afeb 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -37,7 +37,7 @@ import {PasswordStrengthMeterComponent} from 'angular-password-strength-meter';
 import {AboutComponent} from './about/about.component';
 import {ChangelogComponent} from './changelog/changelog.component';
 import {NotificationService} from '../service/notification.service';
-import {RECAPTCHA_V3_SITE_KEY, RecaptchaV3Module} from 'ng-recaptcha';
+import {RECAPTCHA_V3_SITE_KEY, RecaptchaModule, RecaptchaV3Module} from 'ng-recaptcha';
 import {SingleCommentComponent} from './comments/single-comment/single-comment.component';
 import {TranslateStateModule} from './translate-state/translate-state.module';
 import {MinLengthDirective} from '../directive/min-length.directive';
@@ -60,6 +60,11 @@ import {SortableHeaderDirective} from '../service/sort-domain.directive';
 import {InputTextModule} from 'primeng/inputtext';
 import { DomainNamespaceAnnotationsComponent } from './domain-namespace-annotations/domain-namespace-annotations.component';
 import { provideZxvbnServiceForPSM  } from 'angular-password-strength-meter/zxcvbn';
+import { AccessTokensComponent } from './users/access-token/access-tokens.component';
+import { InputGroupModule } from 'primeng/inputgroup';
+import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
+import { ButtonModule } from 'primeng/button';
+import { BrowserModule } from '@angular/platform-browser';
 
 
 @NgModule({
@@ -70,7 +75,6 @@ import { provideZxvbnServiceForPSM  } from 'angular-password-strength-meter/zxcv
         ServicesModule,
         RouterModule,
         ReactiveFormsModule,
-        RecaptchaV3Module,
         PasswordStrengthMeterComponent,
         TranslateModule.forChild(),
         NgxPaginationModule,
@@ -79,6 +83,10 @@ import { provideZxvbnServiceForPSM  } from 'angular-password-strength-meter/zxcv
         DropdownModule,
         InputTextModule,
         FormioModule,
+        InputGroupModule,
+        InputGroupAddonModule,
+        ButtonModule,
+        RecaptchaV3Module
     ],
     declarations: [
         RateComponent,
@@ -123,7 +131,8 @@ import { provideZxvbnServiceForPSM  } from 'angular-password-strength-meter/zxcv
         ContactComponent,
         PreferencesComponent,
         SortableHeaderDirective,
-        DomainNamespaceAnnotationsComponent
+        DomainNamespaceAnnotationsComponent,
+        AccessTokensComponent
     ],
     providers: [
         PasswordValidator,
@@ -174,7 +183,8 @@ import { provideZxvbnServiceForPSM  } from 'angular-password-strength-meter/zxcv
         ModalProvideSshKeyComponent,
         PreferencesComponent,
         SortableHeaderDirective,
-        DomainNamespaceAnnotationsComponent
+        DomainNamespaceAnnotationsComponent,
+        AccessTokensComponent
     ]
 })
 export class SharedModule {
diff --git a/src/app/shared/users/access-token/access-token.ts b/src/app/shared/users/access-token/access-token.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7e0eb1e41bbaf717eedf8e5b4d1982b298f960b3
--- /dev/null
+++ b/src/app/shared/users/access-token/access-token.ts
@@ -0,0 +1,7 @@
+export class AccessToken {
+    public id: number
+    public name: string
+    public userId: number
+    public tokenValue: string
+    public valid: boolean
+}
\ No newline at end of file
diff --git a/src/app/shared/users/access-token/access-tokens.component.html b/src/app/shared/users/access-token/access-tokens.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..9800061a0e11a4ba58e277a6b890c392c71b1b15
--- /dev/null
+++ b/src/app/shared/users/access-token/access-tokens.component.html
@@ -0,0 +1,80 @@
+<div style="margin-bottom: 15px;" class="panel panel-default">
+    <div class="panel-heading">{{'TOKENS.HEADER' | translate}}</div>
+    <div class="panel-body">
+        <table class="table table-hover" aria-describedby="User access tokens table">
+            <thead>
+            <tr>
+                <th scope="col">{{'TOKENS.TABLE.ID' | translate}}</th>
+                <th scope="col">{{'TOKENS.TABLE.NAME' | translate}}</th>
+                <th scope="col">{{'TOKENS.TABLE.VALUE' | translate}}</th>
+                <th scope="col">{{'TOKENS.TABLE.VALID' | translate}}</th>
+                <th scope="col">{{'TOKENS.TABLE.ACTIONS' | translate}}</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr *ngFor="let token of tokensList">
+                <td>{{token.id}}</td>
+                <td>{{token.name}}</td>
+                <td>{{token.tokenValue}}</td>
+                <td>{{token.valid}}</td>
+                <td *ngIf="token.valid">
+                    <button type="button" class="btn btn-danger"
+                            (click)="invalidate(token.id)">{{'TOKENS.BUTTON_INVALIDATE' | translate}}</button>
+                </td>
+                <td *ngIf="!token.valid">
+                    <button type="button" class="btn btn-danger"
+                            (click)="deleteToken(token.id)">{{'TOKENS.BUTTON_DELETE' | translate}}</button>
+                </td>
+            </tr>
+            <tr *ngIf="tokensList.length === 0">
+                <td colspan="3" style="text-align: center">{{'TOKENS.NO_TOKENS' | translate}}</td>
+            </tr>
+            </tbody>
+        </table>
+        <div>
+            <button type="button" class="btn btn-success"
+                    (click)="modal.show()">{{'TOKENS.NEW_TOKEN' | translate}}</button>
+
+        </div>
+    </div>
+</div>
+
+<nmaas-modal styleModal="info">
+    <div class="nmaas-modal-header">{{'TOKENS.MODAL.HEADER' | translate}}</div>
+    <div class="nmaas-modal-body" style="height: 60%; max-height: 80vh;overflow-y: auto;">
+        <form *ngIf="!showCopyToken" [formGroup]="requestForm" (ngSubmit)="createNewToken()">
+            <div class="form-group">
+                <label class="control-label" for="new-token-name">
+                    {{'TOKENS.MODAL.NAME' | translate}}:
+                </label>
+                <input id="new-token-name" type="text" class="form-control" formControlName="name">
+            </div>
+            <div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
+                <div *ngIf="name.errors.required">{{'SSH_KEYS.MODAL.ERROR.NAME_REQUIRED' | translate}}</div>
+                <div *ngIf="name.errors.minlength">{{'SSH_KEYS.MODAL.ERROR.NAME_MINLENGTH' | translate}}</div>
+                <div *ngIf="name.errors.maxlength">{{'SSH_KEYS.MODAL.ERROR.NAME_MAXLENGTH' | translate}}</div>
+                <div *ngIf="name.errors.notUnique">{{name.errors.message}}</div>
+
+            </div>
+            <input type="submit" class="btn btn-success" value="{{'SSH_KEYS.MODAL.BUTTON_ADD' | translate}}"
+                   [disabled]="!requestForm.valid">
+            <button type="button" class="btn btn-primary pull-right"
+                    (click)="modal.hide()">{{'SSH_KEYS.MODAL.BUTTON_CANCEL' | translate}}</button>
+
+        </form>
+        <div *ngIf="showCopyToken">
+                <span class="text-bold">
+                    {{"TOKENS.MODAL.TOKEN_COPY" | translate}}
+                </span>
+                <div>
+                    <p-inputGroup>
+                        <input pInputText [(ngModel)]="newToken.tokenValue"  readonly="true"  placeholder="Token to copy" />
+                        <button class="btn btn-secondary" type="button" (click)="copyToClipboard()">{{"TOKENS.MODAL.COPY" | translate}}</button>
+                    </p-inputGroup>
+                </div>
+                <div class="mt-6 flex ">
+                    <button class="btn btn-primary" type="button"  (click)="ConfirmAndClose()"  >{{"TOKENS.MODAL.TOKEN_SAVED" | translate}}</button>
+                </div>
+        </div>
+    </div>
+</nmaas-modal>
\ No newline at end of file
diff --git a/src/app/shared/users/access-token/access-tokens.component.spec.ts b/src/app/shared/users/access-token/access-tokens.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..98e26efb7ba9c778fb53e550ba27eec87ff1677f
--- /dev/null
+++ b/src/app/shared/users/access-token/access-tokens.component.spec.ts
@@ -0,0 +1,38 @@
+import {ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {AccessTokensComponent} from './access-tokens.component';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-translate/core';
+import {ReactiveFormsModule} from '@angular/forms';
+import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
+
+describe('AccessTokensComponent', () => {
+    let component: AccessTokensComponent;
+    let fixture: ComponentFixture<AccessTokensComponent>;
+
+    beforeEach(async () => {
+        await TestBed.configureTestingModule({
+            declarations: [AccessTokensComponent],
+            imports: [
+                HttpClientTestingModule,
+                ReactiveFormsModule,
+                TranslateModule.forRoot({
+                    loader: {
+                        provide: TranslateLoader,
+                        useClass: TranslateFakeLoader
+                    }
+                }),
+            ],
+            schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
+        })
+            .compileComponents();
+
+        fixture = TestBed.createComponent(AccessTokensComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
\ No newline at end of file
diff --git a/src/app/shared/users/access-token/access-tokens.component.ts b/src/app/shared/users/access-token/access-tokens.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d3123d0cb97493131055103be59bf0058edb79c9
--- /dev/null
+++ b/src/app/shared/users/access-token/access-tokens.component.ts
@@ -0,0 +1,100 @@
+
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {Observable} from 'rxjs';
+import {AccessToken} from './access-token';
+import {AccessTokenService} from './access-tokens.service';
+import {ModalComponent} from '../../modal';
+import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms';
+
+@Component({
+    selector: 'app-access-tokens',
+    templateUrl: './access-tokens.component.html',
+    styleUrls: []
+})
+export class AccessTokensComponent implements OnInit {
+
+    public tokens: Observable<AccessToken[]> = undefined;
+    public tokensList: AccessToken[] = [];
+
+    public requestForm: UntypedFormGroup = undefined;
+
+    public newTokenName = '';
+
+    public showCopyToken = false;
+    public newToken :AccessToken;
+
+    @ViewChild(ModalComponent, {static: true})
+    public readonly modal: ModalComponent;
+
+    constructor(private tokenService: AccessTokenService,
+                private formBuilder: UntypedFormBuilder) {
+    }
+
+    ngOnInit() {
+        this.requestForm = this.formBuilder.group({
+            name: ['', [Validators.required, Validators.minLength(1), Validators.maxLength(16)]],
+        })
+
+        this.tokens = this.tokenService.getAll();
+        this.getData();
+    }
+
+    getData() {
+        this.tokensList = [];
+        this.tokens.subscribe(
+            data => this.tokensList.push(...data),
+            error => console.error(error)
+        )
+    }
+
+    invalidate(id: number) {
+        this.tokenService.invalidate(id).subscribe(
+            (_) => this.getData(),
+            error => console.error(error)
+        );
+    }
+
+    deleteToken(id: number) {
+        this.tokenService.deleteToken(id).subscribe(
+            (_) => this.getData(),
+            error => console.error(error.err)
+        );
+    }
+
+    public createNewToken() {
+        this.tokenService.createToken(this.requestForm.value.name.trim()).subscribe({
+            next: val => {
+                this.requestForm.reset();
+                this.showCopyToken = true;
+                this.newToken = val;
+            },
+            error: err => {
+                console.warn(err.error)
+                this.requestForm.controls['name'].setErrors({notUnique: true, message: err.error}); 
+                console.log(this.requestForm)
+            }
+        })
+    }
+
+    public copyToClipboard() {
+        if (this.newToken.tokenValue) {
+            navigator.clipboard.writeText(this.newToken.tokenValue).then(() => {
+                console.log('Copied to clipbord');
+            }, (err) => {
+                console.error('Some errors accoured: ', err);
+            });
+        }
+    }
+
+    public ConfirmAndClose() {
+        this.showCopyToken = false;
+        this.newToken = null;
+        this.getData();
+        this.modal.hide();
+       
+    }
+
+    get name() {
+        return this.requestForm.get('name');
+    }
+}
\ No newline at end of file
diff --git a/src/app/shared/users/access-token/access-tokens.service.ts b/src/app/shared/users/access-token/access-tokens.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e3c8dec74292a256c24e33a3bade736e7928ec5b
--- /dev/null
+++ b/src/app/shared/users/access-token/access-tokens.service.ts
@@ -0,0 +1,36 @@
+import {Observable} from 'rxjs';
+import {AccessToken} from './access-token';
+import {Injectable} from '@angular/core';
+import {GenericDataService} from '../../../service/genericdata.service';
+import {HttpClient} from '@angular/common/http';
+import {AppConfigService} from '../../../service';
+
+@Injectable({
+    providedIn: 'root'
+})
+export class AccessTokenService extends GenericDataService {
+
+    constructor(http: HttpClient, appConfig: AppConfigService) {
+        super(http, appConfig);
+    }
+
+    public getAll(): Observable<AccessToken[]> {
+        return this.http.get<AccessToken[]>(this.getUrl())
+    }
+
+    public invalidate(id: number): Observable<void> {
+        return this.http.put<void>(`${this.getUrl()}/${id}`, '')
+    }
+
+    public deleteToken(id: number): Observable<void> {
+        return this.http.put<void>(`${this.getUrl()}/delete/${id}`, '')
+    }
+
+    public createToken(tokenName: string): Observable<AccessToken> {
+        return this.http.post<AccessToken>(this.getUrl(), tokenName)
+    }
+
+    private getUrl(): string {
+        return this.appConfig.getApiUrl() + '/tokens';
+    }
+}
\ No newline at end of file
diff --git a/src/app/shared/users/list/userslist.component.html b/src/app/shared/users/list/userslist.component.html
index dcae8ac082f4203c553b5edad904b31c99eabb05..ab667693d70a8c9238af517b063e3cea502bbca0 100644
--- a/src/app/shared/users/list/userslist.component.html
+++ b/src/app/shared/users/list/userslist.component.html
@@ -3,7 +3,7 @@
         {{ 'USERS.TITLE' | translate }}</h3>
     <div class="flex space-between">
         <div class="flex">
-            <button *ngIf="authService.hasDomainRole(domainId, 'ROLE_DOMAIN_ADMIN') || authService.hasDomainRole(domainId, 'ROLE_VL_DOMAIN_ADMIN')"
+            <button *ngIf="authService.hasDomainRole(domainId, 'ROLE_DOMAIN_ADMIN') || authService.hasDomainRole(domainId, 'ROLE_GROUP_DOMAIN_ADMIN')"
                     class="btn btn-primary" (click)="changeMode()">
                 <span *ngIf="isModeAllowed(ComponentMode.DELETE)">{{'USERS.ADD_TO_DOMAIN_BUTTON' | translate}}</span>
                 <span *ngIf="isModeAllowed(ComponentMode.EDIT)">{{'USERS.GO_BACK_BUTTON' | translate}}</span>
diff --git a/src/app/shared/users/new-ssh-key/new-ssh-key.component.ts b/src/app/shared/users/new-ssh-key/new-ssh-key.component.ts
index 619104369b0f33a17d8f96fb4aaa925f0d1a573a..191b25ae717054a9c62fa618cadd1568f2fb31db 100644
--- a/src/app/shared/users/new-ssh-key/new-ssh-key.component.ts
+++ b/src/app/shared/users/new-ssh-key/new-ssh-key.component.ts
@@ -1,4 +1,4 @@
-import {Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
+import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
 import {SSHKeyService} from '../../../service/sshkey.service';
 import {SSHKeyRequest} from '../../../model/sshkey-request';
 import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms';
@@ -17,6 +17,12 @@ export class NewSshKeyComponent implements OnInit {
   @Output()
   public out: EventEmitter<any> = new EventEmitter<any>();
 
+  @Input()
+  public userMode = false;
+  
+  @Input()
+  public userId : number;
+
   public error: string = undefined;
 
   public requestForm: UntypedFormGroup = undefined;
@@ -38,17 +44,34 @@ export class NewSshKeyComponent implements OnInit {
     console.log(this.requestForm);
     request.name = this.requestForm.value.name.trim();
     request.key = this.requestForm.value.key.trim();
+    if(this.userMode) {
+      if(this.userId !== null) {
+        this.keyService.createKeyForUser(request, this.userId).subscribe(
+          data => {
+            this.error = undefined;
+            this.requestForm.reset();
+            this.modal.hide();
+            this.out.emit();
+          },
+          error => {
+            this.error = error.message;
+          }
+      );
+      }
+  } else { // profile view
     this.keyService.createKey(request).subscribe(
-        data => {
-          this.error = undefined;
-          this.requestForm.reset();
-          this.modal.hide();
-          this.out.emit();
-        },
-        error => {
-          this.error = error.message;
-        }
-    );
+      data => {
+        this.error = undefined;
+        this.requestForm.reset();
+        this.modal.hide();
+        this.out.emit();
+      },
+      error => {
+        this.error = error.message;
+      }
+  );
+  }
+    
   }
 
   get name() {
diff --git a/src/app/shared/users/privileges/userprivileges.component.ts b/src/app/shared/users/privileges/userprivileges.component.ts
index a79b06dc31f7548cedea9b393c72cc847efbe11c..5c7e8d99875729dbfc43be8c7bab9b8e6920bd83 100644
--- a/src/app/shared/users/privileges/userprivileges.component.ts
+++ b/src/app/shared/users/privileges/userprivileges.component.ts
@@ -57,7 +57,7 @@ export class UserPrivilegesComponent extends BaseComponent implements OnInit {
         if (this.authService.hasRole(Role[Role.ROLE_SYSTEM_ADMIN]) &&
             Number(this.newPrivilegeForm.get('domainId').value) === this.domainService.getGlobalDomainId()) {
             // admin (global) role set
-            roles = [Role.ROLE_OPERATOR, Role.ROLE_TOOL_MANAGER, Role.ROLE_SYSTEM_ADMIN, Role.ROLE_VL_MANAGER];
+            roles = [Role.ROLE_OPERATOR, Role.ROLE_TOOL_MANAGER, Role.ROLE_SYSTEM_ADMIN, Role.ROLE_GROUP_MANAGER];
             roles = this.filterRoles(roles, this.newPrivilegeForm.get('domainId').value);
         } else if (this.newPrivilegeForm.get('domainId').value != null) {
             // default (domain) role set
diff --git a/src/app/shared/users/ssh-keys/ssh-keys.component.html b/src/app/shared/users/ssh-keys/ssh-keys.component.html
index efb4cb027d9813f2b99c014a6a7894b6ea6e829d..e9025bddb5cd7796a569b04f68bb8cd26b94c772 100644
--- a/src/app/shared/users/ssh-keys/ssh-keys.component.html
+++ b/src/app/shared/users/ssh-keys/ssh-keys.component.html
@@ -1,8 +1,8 @@
-<div style="margin-bottom: 120px;" class="panel panel-default">
+<div style="margin-bottom: 15px;" class="panel panel-default">
     <div class="panel-heading">{{'SSH_KEYS.HEADER' | translate}}</div>
     <div class="panel-body">
         <div class="flex justify-content-end mb-4">
-            <app-new-ssh-key (out)="getData()"></app-new-ssh-key>
+            <app-new-ssh-key [userMode]="userMode" [userId]="userId" (out)="getData()"></app-new-ssh-key>
         </div>
         <table class="table table-hover" aria-describedby="User ssh keys table">
             <thead>
diff --git a/src/app/shared/users/ssh-keys/ssh-keys.component.ts b/src/app/shared/users/ssh-keys/ssh-keys.component.ts
index 8bee8e6e677c36590e4fcd6a4b9a71725f0ec2c9..7def6034efd3074b784ac160800ff63b92dc70c5 100644
--- a/src/app/shared/users/ssh-keys/ssh-keys.component.ts
+++ b/src/app/shared/users/ssh-keys/ssh-keys.component.ts
@@ -1,4 +1,4 @@
-import {Component, OnInit} from '@angular/core';
+import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
 import {SSHKeyService} from '../../../service/sshkey.service';
 import {Observable} from 'rxjs';
 import {SSHKeyView} from '../../../model/sshkey-view';
@@ -8,16 +8,37 @@ import {SSHKeyView} from '../../../model/sshkey-view';
   templateUrl: './ssh-keys.component.html',
   styleUrls: ['./ssh-keys.component.css']
 })
-export class SshKeysComponent implements OnInit {
+export class SshKeysComponent implements OnInit, OnChanges {
 
   public keys: Observable<SSHKeyView[]> = undefined;
   public keysList: SSHKeyView[] = [];
 
+  @Input()
+  public userMode = false;
+
+  @Input()
+  public userId : number;
+
   constructor(private keyService: SSHKeyService) { }
 
   ngOnInit() {
-    this.keys = this.keyService.getAll();
-    this.getData();
+    if(this.userMode) {
+        if(this.userId !== null) {
+            this.keys = this.keyService.getAllByUserId(this.userId);
+            this.getData();
+        }
+    } else { // profile view
+        this.keys = this.keyService.getAll();
+        this.getData();
+    }
+   
+  }
+
+  ngOnChanges(changes: SimpleChanges) {
+    if (changes['userId']) {
+        this.ngOnInit();
+      console.log('Nowa wartość userId:', this.userId);
+    }
   }
 
   getData() {
@@ -33,15 +54,28 @@ export class SshKeysComponent implements OnInit {
   }
 
   invalidate(id: number) {
-      this.keyService.invalidate(id).subscribe(
-          data => {
-              console.log('invalidating ssh key id: ' + id + ' success');
-              this.getData();
-          },
-          error => {
-              console.error(error);
-          }
-      );
+    if(this.userMode) {
+        this.keyService.invalidateUserKey(id, this.userId).subscribe(
+            data => {
+                console.log('invalidating ssh key id: ' + id + ' success');
+                this.getData();
+            },
+            error => {
+                console.error(error);
+            }
+        );
+    } else {
+        this.keyService.invalidate(id).subscribe(
+            data => {
+                console.log('invalidating ssh key id: ' + id + ' success');
+                this.getData();
+            },
+            error => {
+                console.error(error);
+            }
+        );
+    }
+      
   }
 
 }
diff --git a/src/app/welcome/complete/complete.component.html b/src/app/welcome/complete/complete.component.html
index 46cef36fa39df40e49ed75893af4cca1c04f3485..64acd24a4363e8f96d10fafc70258bc9b3eaea3c 100644
--- a/src/app/welcome/complete/complete.component.html
+++ b/src/app/welcome/complete/complete.component.html
@@ -6,7 +6,7 @@
                     <div class="row">
                         <div class="col-xs-3"></div>
                         <div class="text-center col-xs-6">
-                            <img alt="Geant logo" src="assets/images/geant-logo-small.png">
+                            <img alt="GÉANT logo" src="assets/images/geant-logo-small.png">
                         </div>
                         <div class="dropdown text-right drop-lang-div col-xs-3">
                             <a style="display: inline-block" class="dropdown-toggle" aria-expanded="false" aria-haspopup="true"
diff --git a/src/app/welcome/link-account/link-account.component.css b/src/app/welcome/link-account/link-account.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/src/app/welcome/link-account/link-account.component.css
@@ -0,0 +1 @@
+
diff --git a/src/app/welcome/link-account/link-account.component.html b/src/app/welcome/link-account/link-account.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..2d75205238a0c5f83811c5aa3ebcb229b4d79d89
--- /dev/null
+++ b/src/app/welcome/link-account/link-account.component.html
@@ -0,0 +1,51 @@
+<div style="display: flex; justify-content: center;">
+    <div style="
+margin-top: 50px;
+ width: 60%
+" class="panel panel-default">
+        <div class="panel-heading">{{ 'ACCOUNT_LINKING.HEADER' | translate }}</div>
+        <div class="panel-body">
+            <form *ngIf="user"
+                  class="form-horizontal" #userDetailsForm="ngForm">
+                <div>
+                    <p>
+                        {{ 'ACCOUNT_LINKING.INFO' | translate }}
+                    </p>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-2 control-label">{{ 'USER_DETAILS.FIRST_NAME' | translate }}</label>
+                    <div class="col-sm-10">
+                        <p class="form-control-static">{{ user.firstname }}</p>
+                    </div>
+                </div>
+
+                <div class="form-group">
+                    <label class="col-sm-2 control-label">{{ 'USER_DETAILS.LAST_NAME' | translate }}</label>
+                    <div class="col-sm-10">
+                        <p class="form-control-static">{{ user.lastname }}</p>
+                    </div>
+                </div>
+
+                <div class="form-group">
+                    <label class="col-sm-2 control-label">{{ 'USER_DETAILS.EMAIL' | translate }}</label>
+                    <div class="col-sm-10">
+                        <p class="form-control-static">{{ user.email }}</p>
+                    </div>
+                </div>
+
+                <div class="form-group">
+                    <label for="password" class="col-sm-2 control-label">{{ 'PASSWORD.PASSWORD' | translate }}</label>
+                    <div class="col-sm-10">
+                        <input type="password" class="form-control" id="password"
+                               name="password" [(ngModel)]="password">
+                    </div>
+                </div>
+                <button type="submit" class="btn btn-primary"
+                        (click)="submit()">{{ 'ACCOUNT_LINKING.CONFIRM' | translate }}
+                </button>
+                <div *ngIf="error" class="alert alert-danger" style="margin-top: 20px">{{error}}</div>
+            </form>
+            <br>
+        </div>
+    </div>
+</div>
diff --git a/src/app/welcome/link-account/link-account.component.spec.ts b/src/app/welcome/link-account/link-account.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0b0a9f98c9b851dbd8f044e900df4b02595ca2ca
--- /dev/null
+++ b/src/app/welcome/link-account/link-account.component.spec.ts
@@ -0,0 +1,57 @@
+import {ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {LinkAccountComponent} from './link-account.component';
+import {ActivatedRoute} from '@angular/router';
+import {of} from 'rxjs';
+import {AuthService} from '../../auth/auth.service';
+import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-translate/core';
+
+describe('LinkAccountComponent', () => {
+    let component: LinkAccountComponent;
+    let fixture: ComponentFixture<LinkAccountComponent>;
+
+    beforeEach(async () => {
+        await TestBed.configureTestingModule({
+            declarations: [LinkAccountComponent],
+            imports: [TranslateModule.forRoot({
+                loader: {
+                    provide: TranslateLoader,
+                    useClass: TranslateFakeLoader
+                }
+            })],
+            providers: [
+                {
+                    provide: ActivatedRoute,
+                    useValue: {
+                        queryParams: of({
+                            oidc_token: 'mocked.jwt.token'
+                        }),
+                        snapshot: {
+                            paramMap: {
+                                get: () => null
+                            }
+                        }
+                    }
+                },
+                {
+                    provide: AuthService,
+                    useValue: {
+                        isLogged: () => true,
+                        oidcLogout: jasmine.createSpy('oidcLogout'),
+                        oidcLinkingLogin: jasmine.createSpy('oidcLinkingLogin').and.returnValue(of({}))
+                    }
+                },
+
+            ]
+        })
+            .compileComponents();
+
+        fixture = TestBed.createComponent(LinkAccountComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/src/app/welcome/link-account/link-account.component.ts b/src/app/welcome/link-account/link-account.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cb60e030f051c169a57b0f1a72394101cee6157d
--- /dev/null
+++ b/src/app/welcome/link-account/link-account.component.ts
@@ -0,0 +1,84 @@
+import {Component, OnDestroy, OnInit} from '@angular/core';
+import {User} from '../../model';
+import {ActivatedRoute, Router} from '@angular/router';
+import jwtDecode from 'jwt-decode';
+import {AuthService} from '../../auth/auth.service';
+import {TranslateService} from '@ngx-translate/core';
+
+
+@Component({
+    selector: 'app-link-account',
+    templateUrl: './link-account.component.html',
+    styleUrl: './link-account.component.css'
+})
+export class LinkAccountComponent implements OnInit, OnDestroy {
+    public user: User;
+    private token: string;
+    public password: string;
+    public error: string;
+
+    constructor(
+        private readonly route: ActivatedRoute,
+        private readonly authService: AuthService,
+        private readonly router: Router,
+        private translate: TranslateService,
+    ) {
+    }
+
+    ngOnDestroy() {
+        if (!this.authService.isLogged()) {
+            this.authService.oidcLogout(this.token)
+        }
+    }
+
+    ngOnInit() {
+        this.route.queryParams.subscribe(param => {
+            this.token = param['oidc_token'];
+            const decoded: TokenPayload = jwtDecode<TokenPayload>(this.token);
+            this.user = new User();
+            this.user.username = decoded.sub;
+            this.user.firstname = decoded.given_name;
+            this.user.lastname = decoded.family_name;
+            this.user.email = decoded.email;
+        })
+
+    }
+
+    public submit(): void {
+        this.authService.oidcLinkingLogin(
+            this.token,
+            this.user.email,
+            this.password,
+            this.user.username,
+            this.user.firstname,
+            this.user.lastname,
+        ).subscribe(
+            () => {
+                this.router.navigate(['/']);
+            },
+            err => {
+                this.error = this.translate.instant(this.getMessage(err));
+            }
+        )
+    }
+    private getMessage(err: any): string {
+        switch (err['status']) {
+            case 401:
+                return 'LOGIN.LOGIN_FAILURE_MESSAGE';
+            case 406:
+                return 'LOGIN.APPLICATION_UNDER_MAINTENANCE_MESSAGE';
+            case 409:
+                return 'GENERIC_MESSAGE.UNAVAILABLE_MESSAGE';
+            default:
+                return 'GENERIC_MESSAGE.UNAVAILABLE_MESSAGE';
+        }
+    }
+}
+
+
+interface TokenPayload {
+    sub: string;
+    email: string;
+    given_name: string;
+    family_name: string;
+}
diff --git a/src/app/welcome/login/login.component.html b/src/app/welcome/login/login.component.html
index 7084ea8ee9fea6a7682da1aea6576fc41164ee15..af758ef732c5a46c8e251d7f66b454f6ae62ec88 100644
--- a/src/app/welcome/login/login.component.html
+++ b/src/app/welcome/login/login.component.html
@@ -26,20 +26,13 @@
     </fieldset>
 </form>
 <div class="form-group">
-    <button type="submit" (click)="triggerSSO()" class="btn btn-primary btn-block"
+    <button type="submit" (click)="triggerOIDC()" class="btn btn-primary btn-block"
             [disabled]="!this.configuration?.ssoLoginAllowed || loading || ssoLoading">
         {{ 'LOGIN.LOGIN_WITH' | translate }}
     </button>
     <img alt="sso" *ngIf="ssoLoading" src="data:"/>
     <div *ngIf="ssoError" class="alert alert-danger">{{ssoError}}</div>
 </div>
-<div class="form-group">
-    <button type="submit" (click)="triggerOIDC()" class="btn btn-primary btn-block">
-        {{ 'LOGIN.LOGIN_WITH' | translate }}
-    </button>
-    <img alt="sso" *ngIf="ssoLoading" src="data:"/>
-    <div *ngIf="ssoError" class="alert alert-danger">{{ssoError}}</div>
-</div>
 <div class="form-group" style="text-align: center">
     <a (click)="resetPassword = !resetPassword">{{ 'RESET_PASSWORD.FORGOT_PASSWORD_BUTTON' | translate }}</a>
 </div>
diff --git a/src/app/welcome/login/login.component.spec.ts b/src/app/welcome/login/login.component.spec.ts
index 35e39bc620879877c64f1d11636786124b0439f8..f5ebbcf5ea4bef842108fda08b35ae7bdc1dd7d4 100644
--- a/src/app/welcome/login/login.component.spec.ts
+++ b/src/app/welcome/login/login.component.spec.ts
@@ -7,7 +7,6 @@ import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-transl
 import {ModalComponent} from '../../shared/modal';
 import {AuthService} from '../../auth/auth.service';
 import {ConfigurationService, UserService} from '../../service';
-import {SSOService} from '../../service/sso.service';
 import createSpyObj = jasmine.createSpyObj;
 import {of} from 'rxjs';
 import { HttpClientTestingModule } from '@angular/common/http/testing';
@@ -40,7 +39,6 @@ describe('Component: Login', () => {
             providers: [
                 {provide: AuthService, useValue: {}},
                 {provide: ConfigurationService, useValue: configServiceSpy},
-                {provide: SSOService, useValue: {}},
                 {provide: UserService, useValue: {}},
             ],
         }).compileComponents();
diff --git a/src/app/welcome/login/login.component.ts b/src/app/welcome/login/login.component.ts
index dbfcc78194a47a0585edbfd2d35d4b8ee52d32ff..0a4481b66e12318164be2249a30b512a6dfcf0c9 100644
--- a/src/app/welcome/login/login.component.ts
+++ b/src/app/welcome/login/login.component.ts
@@ -4,7 +4,6 @@ import {Router} from '@angular/router';
 import {AuthService} from '../../auth/auth.service';
 import {AppConfigService, ConfigurationService, UserService} from '../../service';
 import {Configuration} from '../../model/configuration';
-import {SSOService} from '../../service/sso.service';
 import {SSOConfig} from '../../model/sso';
 import {UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms';
 import {ModalComponent} from '../../shared/modal';
@@ -34,7 +33,6 @@ export class LoginComponent implements OnInit {
     constructor(private router: Router,
                 private auth: AuthService,
                 private configService: ConfigurationService,
-                private ssoService: SSOService,
                 private fb: UntypedFormBuilder,
                 private userService: UserService,
                 private translate: TranslateService,
@@ -47,12 +45,6 @@ export class LoginComponent implements OnInit {
     ngOnInit() {
         this.configService.getConfiguration().subscribe(config => {
             this.configuration = config;
-            if (config.ssoLoginAllowed) {
-                this.ssoService.getOne().subscribe(sso => {
-                    this.ssoConfig = sso;
-                    this.checkSSO();
-                });
-            }
         });
     }
 
@@ -72,42 +64,13 @@ export class LoginComponent implements OnInit {
         );
     }
 
+    // only for use in linking accounts
     public triggerOIDC() {
-        window.location.href = this.appConfig.getOidcUrl();
-    }
-
-    public checkSSO() {
-        const params = this.router.parseUrl(this.router.url).queryParams;
-
-        if ('ssoUserId' in params) {
-            // Got auth data, send to api
-            this.ssoLoading = true;
-            this.ssoError = '';
-            this.auth.propagateSSOLogin(params.ssoUserId).subscribe(
-                result => {
-                    if (result === true) {
-                        this.ssoLoading = false;
-                        this.translate.setDefaultLang(this.auth.getSelectedLanguage());
-                        this.translate.use(this.auth.getSelectedLanguage());
-                        this.router.navigate(['/']);
-                    } else {
-                        this.ssoError = 'Failed to propagate SSO user id';
-                        this.ssoLoading = false;
-                    }
-                },
-                err => {
-                    this.ssoError = this.translate.instant(this.getMessage(err));
-                    this.ssoLoading = false;
-                }
-            );
+        if (!this.configuration.maintenance) {
+            window.location.href = this.appConfig.getOidcUrl();
         }
     }
 
-    public triggerSSO() {
-        const url = window.location.href.replace(/ssoUserId=.+/, '');
-        window.location.href = this.ssoConfig.loginUrl + '?return=' + url;
-    }
-
     public sendResetNotification() {
         if (this.resetPasswordForm.valid) {
             this.userService.resetPasswordNotification(this.resetPasswordForm.controls['email'].value).subscribe(
diff --git a/src/app/welcome/logout/logout.component.spec.ts b/src/app/welcome/logout/logout.component.spec.ts
index e2e7d4c106d3cb949a4e25bd17b26566d346b828..8db6bfeb9cc5fdfee95e2aea5e4e64266bb7f9db 100644
--- a/src/app/welcome/logout/logout.component.spec.ts
+++ b/src/app/welcome/logout/logout.component.spec.ts
@@ -6,7 +6,6 @@ import createSpyObj = jasmine.createSpyObj;
 import {of} from 'rxjs';
 import {AuthService} from '../../auth/auth.service';
 import {ConfigurationService} from '../../service';
-import {SSOService} from '../../service/sso.service';
 
 describe('LogoutComponent', () => {
     let component: LogoutComponent;
@@ -29,7 +28,6 @@ describe('LogoutComponent', () => {
             providers: [
                 {provide: AuthService, useValue: authServiceSpy},
                 {provide: ConfigurationService, useValue: configServiceSpy},
-                {provide: SSOService, useValue: {}}
             ]
         })
             .compileComponents();
diff --git a/src/app/welcome/logout/logout.component.ts b/src/app/welcome/logout/logout.component.ts
index fb9c9e8263c2d0187a1cbcb3dd76bcee4bd1e3b1..4eaaa50f7df58c9ae99dccb68665c21597a652c5 100644
--- a/src/app/welcome/logout/logout.component.ts
+++ b/src/app/welcome/logout/logout.component.ts
@@ -3,7 +3,6 @@ import { Component, OnInit } from '@angular/core';
 import { Router } from '@angular/router';
 import { AuthService } from '../../auth/auth.service';
 import {ConfigurationService} from '../../service';
-import {SSOService} from '../../service/sso.service';
 
 
 @Component({
@@ -15,21 +14,12 @@ export class LogoutComponent implements OnInit {
 
   constructor(private router: Router,
               private auth: AuthService,
-              private configService: ConfigurationService,
-              private ssoService: SSOService) { }
+              private configService: ConfigurationService) { }
 
   ngOnInit() {
       this.auth.logout();
       this.configService.getConfiguration().subscribe(config => {
-          if (config.ssoLoginAllowed && this.auth.loginUsingSsoService) {
-              const url = window.location.origin;
-              this.ssoService.getOne().subscribe(sso => {
-                  // Shibboleth SP uses parameter 'target' instead of 'return'
-                  window.location.href = sso.logoutUrl + '?return=' + url;
-              });
-          } else {
               this.router.navigate(['/welcome']);
-          }
       });
   }
 
diff --git a/src/app/welcome/passwordreset/password-reset.component.html b/src/app/welcome/passwordreset/password-reset.component.html
index c62301d65a9f27622c178c45b8c299fa04ca760a..8c60eb985068cb262ef92924dabd30b0ca432958 100644
--- a/src/app/welcome/passwordreset/password-reset.component.html
+++ b/src/app/welcome/passwordreset/password-reset.component.html
@@ -4,7 +4,7 @@
       <div class="panel panel-default login-vertical-offset">
         <div class="panel-heading">
           <div class="text-center">
-            <img alt="Geant logo" src="assets/images/geant-logo-small.png">
+            <img alt="GÉANT logo" src="assets/images/geant-logo-small.png">
           </div>
         </div>
         <div class="panel-body" *ngIf="user">
diff --git a/src/app/welcome/passwordreset/password-reset.component.ts b/src/app/welcome/passwordreset/password-reset.component.ts
index 3694303c9c9f26926dba0b28bdb272d824c56160..755353da38a280b7147aab06bece2072de01f587 100644
--- a/src/app/welcome/passwordreset/password-reset.component.ts
+++ b/src/app/welcome/passwordreset/password-reset.component.ts
@@ -58,8 +58,11 @@ export class PasswordResetComponent implements OnInit {
     public resetPassword() {
         if (this.form.valid) {
             this.recaptchaV3Service.execute('password_reset').pipe(
-                catchError(_ => of('')), // in case of captcha error return empty token
+                catchError(error => {
+                    console.error(error);
+                    return of(error)}), // in case of captcha error return empty tokenin case of captcha error return empty token
             ).subscribe((captchaToken) => {
+                console.log(captchaToken)
                 this.showLoading = true;
                 this.passwordReset.password = this.form.controls['newPassword'].value;
                 this.passwordReset.token = this.token;
diff --git a/src/app/welcome/profile/profile.component.html b/src/app/welcome/profile/profile.component.html
index f869b826e6e2744d74e6edf32beee6c2566419a6..f8c17f7e5690bf61858490dcb21e28b1035f820b 100644
--- a/src/app/welcome/profile/profile.component.html
+++ b/src/app/welcome/profile/profile.component.html
@@ -34,5 +34,6 @@
                               [allowedModes]="[ComponentMode.PROFILVIEW, ComponentMode.EDIT]">
         </nmaas-userprivileges>
         <nmaas-ssh-keys></nmaas-ssh-keys>
+        <app-access-tokens></app-access-tokens>
     </div>
 </div>
diff --git a/src/app/welcome/terms-acceptance/terms-acceptance.component.html b/src/app/welcome/terms-acceptance/terms-acceptance.component.html
index ce70113e91c73008691ffb22a2181a56b6a206c0..3605f9376128d984c7d9a38596cbdb918d9373bd 100644
--- a/src/app/welcome/terms-acceptance/terms-acceptance.component.html
+++ b/src/app/welcome/terms-acceptance/terms-acceptance.component.html
@@ -2,7 +2,7 @@
   <div class="row panel panel-default login-vertical-offset col-lg-offset-4 col-lg-4 col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-12">
     <div class="panel-heading">
       <div class="text-center">
-        <img alt="Geant logo" src="assets/images/geant-logo-small.png">
+        <img alt="GÉANT logo" src="assets/images/geant-logo-small.png">
       </div>
     </div>
     <div class="panel-body">
@@ -47,4 +47,4 @@
   </div>
 </nmaas-modal>
 <modal-info-terms></modal-info-terms>
-<modal-info-policy></modal-info-policy>
\ No newline at end of file
+<modal-info-policy></modal-info-policy>
diff --git a/src/app/welcome/welcome.module.ts b/src/app/welcome/welcome.module.ts
index 1e0ecde52c243ae5ed4004c6dce60bbe39f8c075..e212c4f059d959724211aa423e911d38b087f067 100644
--- a/src/app/welcome/welcome.module.ts
+++ b/src/app/welcome/welcome.module.ts
@@ -17,43 +17,44 @@ import {CompleteComponent} from './complete/complete.component';
 import {ContentDisplayService} from '../service/content-display.service';
 import {TermsAcceptanceComponent} from './terms-acceptance/terms-acceptance.component';
 import {TranslateModule} from '@ngx-translate/core';
-import {SSOService} from '../service/sso.service';
 import {PasswordResetComponent} from './passwordreset/password-reset.component';
 import {PasswordStrengthMeterComponent} from 'angular-password-strength-meter';
 import {PolicySubpageComponent} from './policy-subpage/policy-subpage.component';
+import {LinkAccountComponent} from './link-account/link-account.component';
 
 @NgModule({
-  declarations: [
-    WelcomeComponent,
-    LoginComponent,
-    LogoutComponent,
-    RegistrationComponent,
-    ProfileComponent,
-    CompleteComponent,
-    TermsAcceptanceComponent,
-    PasswordResetComponent,
-    PolicySubpageComponent
-  ],
-  imports: [
-    FormsModule,
-    ReactiveFormsModule,
-    CommonModule,
-    RouterModule,
-    SharedModule,
-    PipesModule,
-    AppMarketModule,
-    PasswordStrengthMeterComponent,
-    TranslateModule.forChild()
-  ],
-  exports: [
-    WelcomeComponent
-  ],
-  providers: [
-    RegistrationService,
-    UserService,
-    ChangelogService,
-    ContentDisplayService,
-    SSOService
-  ]
+    declarations: [
+        WelcomeComponent,
+        LoginComponent,
+        LogoutComponent,
+        RegistrationComponent,
+        ProfileComponent,
+        CompleteComponent,
+        TermsAcceptanceComponent,
+        PasswordResetComponent,
+        PolicySubpageComponent,
+        LinkAccountComponent
+    ],
+    imports: [
+        FormsModule,
+        ReactiveFormsModule,
+        CommonModule,
+        RouterModule,
+        SharedModule,
+        PipesModule,
+        AppMarketModule,
+        PasswordStrengthMeterComponent,
+        TranslateModule.forChild()
+    ],
+    exports: [
+        WelcomeComponent
+    ],
+    providers: [
+        RegistrationService,
+        UserService,
+        ChangelogService,
+        ContentDisplayService
+    ]
 })
-export class WelcomeModule {}
+export class WelcomeModule {
+}
diff --git a/src/assets/formio/config-template.json b/src/assets/formio/config-template.json
index 4f01f8c274ec539a2bf97f85f4d91142e72a2bb8..fe79f6dc84e9f22f76f9de4c119e722d51c99ebe 100644
--- a/src/assets/formio/config-template.json
+++ b/src/assets/formio/config-template.json
@@ -15,14 +15,7 @@
               "input": true,
               "tab": 0,
               "key": "configuration",
-              "components": [
-                {
-                  "type": "htmlelement",
-                  "input": false,
-                  "content": "<p>All required configuration should be applied using graphical interface</p>",
-                  "tab": 0
-                }
-              ]
+              "components": []
             }
           ]
         },
diff --git a/src/config.json b/src/config.json
index cf304ab51e9b9163bb4f10cb3b444323cf2bd941..3b4e008b3f93a80b48bfe1b62a590d6efd354817 100644
--- a/src/config.json
+++ b/src/config.json
@@ -1,6 +1,5 @@
 {
 	"apiUrl": "http://localhost:9000/api",
-	"oidcUrl": "http://localhost:9000/oauth2/authorization/my-oidc",
 	"tokenName": "token",
 	"nmaas": {
 		"globalDomainId": 1
diff --git a/src/styles.css b/src/styles.css
index c8a1e4ce5ec367c50bb1b26cf662af0a84ff3270..b3eaa02ccce2b1b94b757865e1477ef33b3061c6 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -92,3 +92,7 @@
 .btn-text:hover{
     background: #EBEEF5;
 }
+
+.text-bold {
+    font-weight: 700;;
+}