diff --git a/src/app/auth/auth.action.spec.ts b/src/app/auth/auth.action.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..76209f4e5a15a19b69c1510cad6e9c322b49894d
--- /dev/null
+++ b/src/app/auth/auth.action.spec.ts
@@ -0,0 +1,37 @@
+import * as authActions from './auth.action';
+import { UserProfile } from './user-profile.model';
+
+describe('[Auth] Action', () => {
+    it('should create LoginAction', () => {
+        const action = new authActions.LoginAction();
+        expect(action.type).toEqual(authActions.LOGIN);
+    });
+
+    it('should create LogoutAction', () => {
+        const action = new authActions.LogoutAction();
+        expect(action.type).toEqual(authActions.LOGOUT);
+    });
+
+    it('should create AuthSuccessAction', () => {
+        const action = new authActions.AuthSuccessAction();
+        expect(action.type).toEqual(authActions.AUTH_SUCCESS);
+    });
+
+    it('should create LoadUserProfileSuccessAction', () => {
+        const profile: UserProfile = { id: 'id', username: 'toto' };
+        const action = new authActions.LoadUserProfileSuccessAction(profile);
+        expect(action.type).toEqual(authActions.LOAD_USER_PROFILE_SUCCESS);
+        expect(action.payload).toEqual(profile);
+    });
+
+    it('should create LoadUserRolesSuccessAction', () => {
+        const action = new authActions.LoadUserRolesSuccessAction(['toto']);
+        expect(action.type).toEqual(authActions.LOAD_USER_ROLES_SUCCESS);
+        expect(action.payload).toEqual(['toto']);
+    });
+
+    it('should create OpenEditProfileAction', () => {
+        const action = new authActions.OpenEditProfileAction();
+        expect(action.type).toEqual(authActions.OPEN_EDIT_PROFILE);
+    });
+});
diff --git a/src/app/auth/auth.action.ts b/src/app/auth/auth.action.ts
index 481b97a2ffcf383dbddec3ac8f6b70c8d762629f..51a8df8bdfac6027bb012d8ed13bbf91970795b8 100644
--- a/src/app/auth/auth.action.ts
+++ b/src/app/auth/auth.action.ts
@@ -1,3 +1,12 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { Action } from '@ngrx/store';
 
 import { UserProfile } from './user-profile.model';
@@ -7,38 +16,68 @@ export const LOGOUT = '[Auth] Logout';
 export const AUTH_SUCCESS = '[Auth] Auth Success';
 export const LOAD_USER_PROFILE_SUCCESS = '[Auth] Load User Profile Success';
 export const LOAD_USER_ROLES_SUCCESS = '[Auth] Load User Roles Success';
-export const OPEN_EDIT_PROFILE = '[Auth] Edit Profile';
+export const OPEN_EDIT_PROFILE = '[Auth] Open Edit Profile';
 
+/**
+ * @class
+ * @classdesc LoginAction action.
+ * @readonly
+ */
 export class LoginAction implements Action {
     readonly type = LOGIN;
 
     constructor(public payload: {} = null) { }
 }
 
+/**
+ * @class
+ * @classdesc LogoutAction action.
+ * @readonly
+ */
 export class LogoutAction implements Action {
     readonly type = LOGOUT;
 
     constructor(public payload: {} = null) { }
 }
 
+/**
+ * @class
+ * @classdesc AuthSuccessAction action.
+ * @readonly
+ */
 export class AuthSuccessAction implements Action {
     readonly type = AUTH_SUCCESS;
 
     constructor(public payload: {} = null) { }
 }
 
+/**
+ * @class
+ * @classdesc LoadUserProfileSuccessAction action.
+ * @readonly
+ */
 export class LoadUserProfileSuccessAction implements Action {
     readonly type = LOAD_USER_PROFILE_SUCCESS;
 
     constructor(public payload: UserProfile) { }
 }
 
+/**
+ * @class
+ * @classdesc LoadUserRolesSuccessAction action.
+ * @readonly
+ */
 export class LoadUserRolesSuccessAction implements Action {
     readonly type = LOAD_USER_ROLES_SUCCESS;
 
     constructor(public payload: string[]) { }
 }
 
+/**
+ * @class
+ * @classdesc OpenEditProfileAction action.
+ * @readonly
+ */
 export class OpenEditProfileAction implements Action {
     readonly type = OPEN_EDIT_PROFILE;
 
diff --git a/src/app/auth/auth.effects.ts b/src/app/auth/auth.effects.ts
index 7f492302140914a38199cc0cb3a47375e3560357..b309dbc1e2b1bb213c11377ba1c9f5cbecb44f73 100644
--- a/src/app/auth/auth.effects.ts
+++ b/src/app/auth/auth.effects.ts
@@ -1,32 +1,55 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { Injectable } from '@angular/core';
-import { from } from 'rxjs';
-import { switchMap, tap } from 'rxjs/operators';
 
 import { Effect, Actions, ofType } from '@ngrx/effects';
+import { from } from 'rxjs';
+import { switchMap, tap } from 'rxjs/operators';
 import { KeycloakService } from 'keycloak-angular';
 
 import * as authActions from './auth.action';
 import { environment } from '../../environments/environment';
 
 @Injectable()
+/**
+ * @class
+ * @classdesc Authentication effects.
+ */
+
 export class AuthEffects {
     constructor(
         private actions$: Actions,
         private keycloak: KeycloakService
     ) { }
 
+    /**
+     * Executes log in.
+     */
     @Effect({ dispatch: false })
     loginAction$ = this.actions$.pipe(
         ofType(authActions.LOGIN),
         tap(_ => this.keycloak.login())
     );
 
+    /**
+     * Executes log out.
+     */
     @Effect({ dispatch: false })
     logoutAction$ = this.actions$.pipe(
         ofType(authActions.LOGOUT),
         tap(_ => this.keycloak.logout())
     );
 
+    /**
+     * Saves user profile and gets user roles.
+     */
     @Effect()
     authSuccessAction$ = this.actions$.pipe(
         ofType(authActions.AUTH_SUCCESS),
@@ -40,6 +63,9 @@ export class AuthEffects {
         )
     );
 
+    /**
+     * Opens edit profile page.
+     */
     @Effect({ dispatch: false })
     OpenEditProfileAction$ = this.actions$.pipe(
         ofType(authActions.OPEN_EDIT_PROFILE),
diff --git a/src/app/auth/auth.module.ts b/src/app/auth/auth.module.ts
index 8d7d58afc16229fe4ca6add1af004262bf99dd60..4f69a3e398dc94c1a8b46c54c3f4146caa123676 100644
--- a/src/app/auth/auth.module.ts
+++ b/src/app/auth/auth.module.ts
@@ -1,12 +1,21 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { NgModule } from '@angular/core';
 
-import { KeycloakAngularModule } from 'keycloak-angular';
 import { StoreModule } from '@ngrx/store';
 import { EffectsModule } from '@ngrx/effects';
+import { KeycloakAngularModule } from 'keycloak-angular';
 
-import { initializeKeycloakAnis } from './init.keycloak';
 import { reducer } from './auth.reducer';
 import { AuthEffects } from './auth.effects';
+import { initializeKeycloakAnis } from './init.keycloak';
 
 @NgModule({
     imports: [
@@ -18,4 +27,8 @@ import { AuthEffects } from './auth.effects';
         initializeKeycloakAnis
     ]
 })
+/**
+ * @class
+ * @classdesc Authentication module.
+ */
 export class AuthModule { }
diff --git a/src/app/auth/auth.reducer.spec.ts b/src/app/auth/auth.reducer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e04ed67dee4b06ff414149506e609b190e0b643f
--- /dev/null
+++ b/src/app/auth/auth.reducer.spec.ts
@@ -0,0 +1,69 @@
+import * as fromAuth from './auth.reducer';
+import * as authActions from './auth.action';
+import { UserProfile } from './user-profile.model';
+
+describe('[Auth] Reducer', () => {
+    it('should return init state', () => {
+        const { initialState } = fromAuth;
+        const action = {} as authActions.Actions;
+        const state = fromAuth.reducer(undefined, action);
+
+        expect(state).toBe(initialState);
+    });
+
+    it('should set isAuthenticated to true', () => {
+        const { initialState } = fromAuth;
+        const action = new authActions.AuthSuccessAction();
+        const state = fromAuth.reducer(initialState, action);
+
+        expect(state.isAuthenticated).toBeTruthy();
+        expect(state.userProfile).toBeNull();
+        expect(state.userRoles.length).toEqual(0);
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set userProfile', () => {
+        const profile: UserProfile = { id: 'id', username: 'toto' };
+        const { initialState } = fromAuth;
+        const action = new authActions.LoadUserProfileSuccessAction(profile);
+        const state = fromAuth.reducer(initialState, action);
+
+        expect(state.isAuthenticated).toBeFalsy();
+        expect(state.userProfile).toEqual(profile);
+        expect(state.userRoles.length).toEqual(0);
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should set userRoles', () => {
+        const { initialState } = fromAuth;
+        const action = new authActions.LoadUserRolesSuccessAction(['toto']);
+        const state = fromAuth.reducer(initialState, action);
+
+        expect(state.isAuthenticated).toBeFalsy();
+        expect(state.userProfile).toBeNull();
+        expect(state.userRoles.length).toEqual(1);
+        expect(state.userRoles[0]).toEqual('toto');
+        expect(state).not.toEqual(initialState);
+    });
+
+    it('should get isAuthenticated', () => {
+        const action = {} as authActions.Actions;
+        const state = fromAuth.reducer(undefined, action);
+
+        expect(fromAuth.isAuthenticated(state)).toBeFalsy();
+    });
+
+    it('should get userProfile', () => {
+        const action = {} as authActions.Actions;
+        const state = fromAuth.reducer(undefined, action);
+
+        expect(fromAuth.getUserProfile(state)).toBeNull();
+    });
+
+    it('should get userRoles', () => {
+        const action = {} as authActions.Actions;
+        const state = fromAuth.reducer(undefined, action);
+
+        expect(fromAuth.getUserRoles(state).length).toEqual(0);
+    });
+});
diff --git a/src/app/auth/auth.reducer.ts b/src/app/auth/auth.reducer.ts
index 576ca0100cf210e755ca825a5195a957a58617c1..2ecad6844a5e9659d225fe22b2cadf63eb387cdb 100644
--- a/src/app/auth/auth.reducer.ts
+++ b/src/app/auth/auth.reducer.ts
@@ -1,7 +1,20 @@
-import * as actions from './auth.action';
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
 
+import * as actions from './auth.action';
 import { UserProfile } from './user-profile.model';
 
+/**
+ * Interface for authentication state.
+ *
+ * @interface State
+ */
 export interface State {
     isAuthenticated: boolean;
     userProfile: UserProfile;
@@ -14,6 +27,14 @@ export const initialState: State = {
     userRoles: []
 };
 
+/**
+ * Reduces state.
+ *
+ * @param  {State} state - The state.
+ * @param  {actions} action - The action.
+ *
+ * @return State
+ */
 export function reducer(state: State = initialState, action: actions.Actions): State {
     switch (action.type) {
         case actions.AUTH_SUCCESS:
@@ -23,19 +44,15 @@ export function reducer(state: State = initialState, action: actions.Actions): S
             };
 
         case actions.LOAD_USER_PROFILE_SUCCESS:
-            const userProfile = action.payload;
-
             return {
                 ...state,
-                userProfile
+                userProfile: action.payload
             };
 
         case actions.LOAD_USER_ROLES_SUCCESS:
-            const userRoles = action.payload;
-
             return {
                 ...state,
-                userRoles
+                userRoles: action.payload
             };
 
         default:
diff --git a/src/app/auth/auth.selector.spec.ts b/src/app/auth/auth.selector.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c07e09681e3f4f580890d17530c6076b0d610803
--- /dev/null
+++ b/src/app/auth/auth.selector.spec.ts
@@ -0,0 +1,19 @@
+import * as authSelector from './auth.selector';
+import * as fromAuth from './auth.reducer';
+
+describe('[Auth] Selector', () => {
+    it('should get isAuthenticated', () => {
+        const state = { auth: { ...fromAuth.initialState }};
+        expect(authSelector.isAuthenticated(state)).toBeFalsy();
+    });
+
+    it('should get userProfile', () => {
+        const state = { auth: { ...fromAuth.initialState }};
+        expect(authSelector.getUserProfile(state)).toBeNull();
+    });
+
+    it('should get userRoles', () => {
+        const state = { auth: { ...fromAuth.initialState }};
+        expect(authSelector.getUserRoles(state).length).toEqual(0);
+    });
+});
diff --git a/src/app/auth/auth.selector.ts b/src/app/auth/auth.selector.ts
index a58dfd67eb2ee9295cbcd18d4df0aa76ac438733..db6ccddec34494926d889d520eecaa85a3918e54 100644
--- a/src/app/auth/auth.selector.ts
+++ b/src/app/auth/auth.selector.ts
@@ -1,3 +1,12 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { createSelector, createFeatureSelector } from '@ngrx/store';
 
 import * as auth from './auth.reducer';
diff --git a/src/app/auth/init.keycloak.ts b/src/app/auth/init.keycloak.ts
index 3b9e98db17f3c6381b1aeabece40054d1196fe5f..9b589434cd55f511bd6702a6bb265d436752210a 100644
--- a/src/app/auth/init.keycloak.ts
+++ b/src/app/auth/init.keycloak.ts
@@ -1,14 +1,32 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
 import { APP_INITIALIZER } from '@angular/core';
-import { from } from 'rxjs';
 
-import { KeycloakService, KeycloakEventType } from 'keycloak-angular';
 import { Store } from '@ngrx/store';
+import { from } from 'rxjs';
+import { KeycloakService, KeycloakEventType } from 'keycloak-angular';
 
 import * as keycloakActions from './auth.action';
 import * as fromKeycloak from './auth.reducer';
 import { environment } from '../../environments/environment';
 
-function initializeKeycloak(keycloak: KeycloakService, store: Store<{ keycloak: fromKeycloak.State }>) {
+/**
+ * Inits Keycloak.
+ *
+ * @param  {KeycloakService} keycloak - The Keycloak service.
+ * @param  {Store<{ keycloak: fromKeycloak.State }>} store - The Keycloak store.
+ *
+ * @return any
+ */
+
+function initializeKeycloak(keycloak: KeycloakService, store: Store<{ keycloak: fromKeycloak.State }>): any {
     return async () => {
         from(keycloak.keycloakEvents$).subscribe(event => {
             if (event.type === KeycloakEventType.OnAuthSuccess) {
@@ -36,5 +54,5 @@ export const initializeKeycloakAnis = {
     provide: APP_INITIALIZER,
     useFactory: initializeKeycloak,
     multi: true,
-    deps: [ KeycloakService, Store ],
+    deps: [ KeycloakService, Store ]
 };
diff --git a/src/app/auth/user-profile.model.ts b/src/app/auth/user-profile.model.ts
index c2addf7e0613e83e9015c843bef7ad7131352113..1848db380bfe6638251dfe12b6ad090c682e8550 100644
--- a/src/app/auth/user-profile.model.ts
+++ b/src/app/auth/user-profile.model.ts
@@ -1,3 +1,18 @@
+/**
+ * This file is part of Anis Client.
+ *
+ * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+
+/**
+ * Interface for user profile.
+ *
+ * @interface UserProfile
+ */
 export interface UserProfile {
     id?: string;
     username?: string;