diff --git a/pom.xml b/pom.xml
index d9fc501a209e58467ba08053907a389ec92b728f..edaf75b174b3890292d26699213332ca44c837fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,27 @@
             <version>3.11</version>
             <scope>test</scope>
         </dependency>
+
+        <!-- JWT -->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+            <version>0.11.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <scope>runtime</scope>
+            <version>0.11.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <version>0.11.2</version>
+            <scope>compile</scope>
+        </dependency>
+
+
     </dependencies>
     <build>
         <plugins>
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
index 84d030b49f97eeb4ccb3158a9daa15976fbb2f2b..a1386c3e07ed48c6544fc2922e4f23ece80818e7 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/model/BiblioModel.java
@@ -3,6 +3,9 @@ package fr.univtln.bruno.samples.jaxrs.model;
 import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException;
 import fr.univtln.bruno.samples.jaxrs.exceptions.NotFoundException;
 import fr.univtln.bruno.samples.jaxrs.resources.PaginationInfo;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.*;
 import jakarta.xml.bind.annotation.XmlAccessType;
 import jakarta.xml.bind.annotation.XmlAccessorType;
 import jakarta.xml.bind.annotation.XmlAttribute;
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
index f346c4d811c898a360346689b6cba256b62b41a3..13596286d94cb7052becf09e9fdb12b7cc8e1f40 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/resources/BiblioResource.java
@@ -5,13 +5,26 @@ import fr.univtln.bruno.samples.jaxrs.exceptions.IllegalArgumentException;
 import fr.univtln.bruno.samples.jaxrs.exceptions.NotFoundException;
 import fr.univtln.bruno.samples.jaxrs.model.BiblioModel;
 import fr.univtln.bruno.samples.jaxrs.model.BiblioModel.Auteur;
+import fr.univtln.bruno.samples.jaxrs.security.BasicAuth;
+import fr.univtln.bruno.samples.jaxrs.security.JWTAuth;
+import fr.univtln.bruno.samples.jaxrs.security.User;
+import fr.univtln.bruno.samples.jaxrs.security.UserDatabase;
 import fr.univtln.bruno.samples.jaxrs.status.Status;
+import io.jsonwebtoken.Jwts;
+import jakarta.annotation.security.RolesAllowed;
 import jakarta.ws.rs.*;
-import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.*;
 import lombok.extern.java.Log;
 
+import javax.naming.AuthenticationException;
 import java.security.SecureRandom;
-import java.util.*;
+import java.sql.Date;
+import java.text.ParseException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
+import java.util.Collection;
+import java.util.List;
 
 @Log
 // The Java class will be hosted at the URI path "/biblio"
@@ -128,4 +141,61 @@ public class BiblioResource {
     public List<Auteur> getAuteursPage(@BeanParam PaginationInfo paginationInfo) {
         return modeleBibliotheque.getWithFilter(paginationInfo);
     }
+
+    @GET
+    @Path("context")
+    @RolesAllowed("ADMIN")
+    public String getContext(@Context UriInfo uriInfo, @Context HttpHeaders httpHeaders, @Context Request request, @Context SecurityContext securityContext) throws ParseException {
+        return "UriInfo: (" + uriInfo.getRequestUri().toString()
+               + ")\n HttpHeaders(" + httpHeaders.getRequestHeaders().toString()
+               //+")\n Request Precondition("+request.evaluatePreconditions(new SimpleDateFormat("dd/MM/yyyy-HH:mm:ss").parse("03/02/2021-10:30:00"))
+               + ")\n SecurityContext(Auth.scheme: [" + securityContext.getAuthenticationScheme()
+               + "] user: [" + securityContext.getUserPrincipal().getName()
+               + "] secured: [" + securityContext.isSecure() + "] )";
+    }
+
+    @GET
+    @Path("adminsonly")
+    @RolesAllowed("ADMIN")
+    @BasicAuth
+    public String getRestrictedToAdmins() {
+        return "secret for admins !";
+    }
+
+    @GET
+    @Path("usersonly")
+    @RolesAllowed("USER")
+    @BasicAuth
+    public String getRestrictedToUsers() {
+        return "secret for users !";
+    }
+
+    @GET
+    @Path("secured")
+    @RolesAllowed({"USER", "ADMIN"})
+    @JWTAuth
+    public String securedByJWT(@Context SecurityContext securityContext) {
+        log.info("USER ACCESS :"+securityContext.getUserPrincipal().getName());
+        return "Access with JWT ok for "+securityContext.getUserPrincipal().getName();
+    }
+
+    @GET
+    @Path("login")
+    @RolesAllowed({"USER", "ADMIN"})
+    @BasicAuth
+    public String login(@Context SecurityContext securityContext) {
+        if (securityContext.isSecure() && securityContext.getUserPrincipal() instanceof User) {
+            User user = (User) securityContext.getUserPrincipal();
+            return Jwts.builder()
+                    .setIssuer("sample-jaxrs")
+                    .setIssuedAt(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()))
+                    .setSubject(user.getEmail())
+                    .claim("firstname", user.getFirstName())
+                    .claim("lastname", user.getLastName())
+                    .claim("roles", user.getRoles())
+                    .setExpiration(Date.from(LocalDateTime.now().plus(15, ChronoUnit.MINUTES).atZone(ZoneId.systemDefault()).toInstant()))
+                    .signWith(UserDatabase.KEY).compact();
+        }
+        throw new WebApplicationException(new AuthenticationException());
+    }
 }
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/AuthenticationFilter.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/AuthenticationFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..17d48f3bd0dddcbeb3cd7d9114e592bb56424267
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/AuthenticationFilter.java
@@ -0,0 +1,125 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import jakarta.annotation.Priority;
+import jakarta.annotation.security.DenyAll;
+import jakarta.annotation.security.PermitAll;
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.SecurityContext;
+import jakarta.ws.rs.ext.Provider;
+import lombok.SneakyThrows;
+import lombok.extern.java.Log;
+
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@BasicAuth
+@Provider
+@Priority(Priorities.AUTHENTICATION)
+@Log
+/**
+ * This class if a filter for JAX-RS to perform authentication and to check permissions against the acceded method.
+ */
+public class AuthenticationFilter implements ContainerRequestFilter {
+    private static final String AUTHORIZATION_PROPERTY = "Authorization";
+    private static final String AUTHENTICATION_SCHEME = "Basic";
+
+    //We inject the data from the acceded resource.
+    @Context
+    private ResourceInfo resourceInfo;
+
+    @SneakyThrows
+    @Override
+    public void filter(ContainerRequestContext requestContext) {
+        //We use reflection on the acceded method to look for security annotations.
+        Method method = resourceInfo.getResourceMethod();
+        //if its PermitAll access is granted
+        //otherwise if its DenyAll the access is refused
+        if (!method.isAnnotationPresent(PermitAll.class)) {
+            if (method.isAnnotationPresent(DenyAll.class)) {
+                requestContext.abortWith(Response.status(Response.Status.FORBIDDEN)
+                        .entity("Access denied to all users").build());
+                return;
+            }
+
+            //We get the authorization header
+            final String authorization = requestContext.getHeaderString(AUTHORIZATION_PROPERTY);
+
+            //We check the presence of the credentials
+            if (authorization == null || authorization.isEmpty()) {
+                requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                        .entity("Please provide your credentials").build());
+                return;
+            }
+
+            //Get encoded username and password
+            final String encodedUserPassword = authorization.substring(AUTHENTICATION_SCHEME.length()).trim();
+
+            //Decode username and password
+            String usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword.getBytes()));
+
+            //Split username and password tokens
+            final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
+            final String username = tokenizer.nextToken();
+            final String password = tokenizer.nextToken();
+
+            log.info(username + " tries to log in with " + password);
+
+            //Verify user access
+            if (method.isAnnotationPresent(RolesAllowed.class)) {
+                RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
+                EnumSet<UserDatabase.Role> rolesSet =
+                        Arrays.stream(rolesAnnotation.value())
+                                .map(r -> UserDatabase.Role.valueOf(r))
+                                .collect(Collectors.toCollection(() -> EnumSet.noneOf(UserDatabase.Role.class)));
+
+                //We check to login/password
+                if (!UserDatabase.USER_DATABASE.checkPassword(username, password)) {
+                    requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Wrong username or password").build());
+                    return;
+                }
+                //We check if the role is allowed
+                if (Collections.disjoint(rolesSet, UserDatabase.USER_DATABASE.getUserRoles(username))) {
+                    requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Roles not allowed").build());
+                    return;
+                }
+
+                //We build a new securitycontext to transmit the security data to JAX-RS
+                requestContext.setSecurityContext(new SecurityContext() {
+
+                    @Override
+                    public Principal getUserPrincipal() {
+                        return UserDatabase.USER_DATABASE.getUser(username);
+                    }
+
+                    @Override
+                    public boolean isUserInRole(String role) {
+                        return UserDatabase.USER_DATABASE.getUserRoles(username).contains(UserDatabase.Role.valueOf(role));
+                    }
+
+                    @Override
+                    public boolean isSecure() {
+                        return true;
+                    }
+
+                    @Override
+                    public String getAuthenticationScheme() {
+                        return AUTHENTICATION_SCHEME;
+                    }
+                });
+
+
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/BasicAuth.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/BasicAuth.java
new file mode 100644
index 0000000000000000000000000000000000000000..458387ed9684cd9a8e37c0ac84d345abae5dd93b
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/BasicAuth.java
@@ -0,0 +1,16 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import jakarta.ws.rs.NameBinding;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@NameBinding
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface BasicAuth {
+}
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JWTAuth.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JWTAuth.java
new file mode 100644
index 0000000000000000000000000000000000000000..00b75227200f20567e1938404897ee454879f9e5
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JWTAuth.java
@@ -0,0 +1,16 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import jakarta.ws.rs.NameBinding;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@NameBinding
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface JWTAuth {
+}
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JsonWebTokenFilter.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JsonWebTokenFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d19aeb0fea9a9b2073db51961f3e86f252270ea
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/JsonWebTokenFilter.java
@@ -0,0 +1,128 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import jakarta.annotation.Priority;
+import jakarta.annotation.security.DenyAll;
+import jakarta.annotation.security.PermitAll;
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.SecurityContext;
+import jakarta.ws.rs.ext.Provider;
+import lombok.SneakyThrows;
+import lombok.extern.java.Log;
+
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.stream.Collectors;
+
+@JWTAuth
+@Provider
+@Priority(Priorities.AUTHENTICATION)
+@Log
+/**
+ * This class if a filter for JAX-RS to perform authentication via JWT.
+ */
+public class JsonWebTokenFilter implements ContainerRequestFilter {
+    private static final String AUTHORIZATION_PROPERTY = "Authorization";
+    private static final String AUTHENTICATION_SCHEME = "Bearer";
+
+    //We inject the data from the acceded resource.
+    @Context
+    private ResourceInfo resourceInfo;
+
+    @SneakyThrows
+    @Override
+    public void filter(ContainerRequestContext requestContext) {
+        //We use reflection on the acceded method to look for security annotations.
+        Method method = resourceInfo.getResourceMethod();
+        //if its PermitAll access is granted
+        //otherwise if its DenyAll the access is refused
+        if (!method.isAnnotationPresent(PermitAll.class)) {
+            if (method.isAnnotationPresent(DenyAll.class)) {
+                requestContext.abortWith(Response.status(Response.Status.FORBIDDEN)
+                        .entity("Access denied to all users").build());
+                return;
+            }
+
+            //We get the authorization header
+            final String authorization = requestContext.getHeaderString(AUTHORIZATION_PROPERTY);
+
+
+            if (method.isAnnotationPresent(RolesAllowed.class)) {
+                RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
+                EnumSet<UserDatabase.Role> rolesSet =
+                        Arrays.stream(rolesAnnotation.value())
+                                .map(r -> UserDatabase.Role.valueOf(r))
+                                .collect(Collectors.toCollection(() -> EnumSet.noneOf(UserDatabase.Role.class)));
+
+
+                //We check the credentials presence
+                if (authorization == null || authorization.isEmpty()) {
+                    requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Please provide your credentials").build());
+                    return;
+                }
+
+                //Gets the token
+                log.info("AUTH: "+authorization);
+                final String compactJwt = authorization.substring(AUTHENTICATION_SCHEME.length()).trim();
+                if (!authorization.contains(AUTHENTICATION_SCHEME) || compactJwt == null || compactJwt.isEmpty()) {
+                    requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Please provide your credentials").build());
+                    return;
+                }
+                log.info("JWT: "+compactJwt);
+
+                Jws<Claims> jws = Jwts.parserBuilder()
+                        .setSigningKey(UserDatabase.KEY)
+                        .build()
+                        .parseClaimsJws(compactJwt);
+                log.info("JWT decoded: "+jws.toString());
+
+                final String username = jws.getBody().getSubject();
+
+                //We check if the role is allowed
+                if (Collections.disjoint(rolesSet, UserDatabase.USER_DATABASE.getUserRoles(username))) {
+                    requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
+                            .entity("Roles not allowed").build());
+                    return;
+                }
+
+                //We build a new securitycontext to transmit the security data to JAX-RS
+                requestContext.setSecurityContext(new SecurityContext() {
+
+                    @Override
+                    public Principal getUserPrincipal() {
+                        return UserDatabase.USER_DATABASE.getUser(username);
+                    }
+
+                    @Override
+                    public boolean isUserInRole(String role) {
+                        return UserDatabase.USER_DATABASE.getUserRoles(username).contains(UserDatabase.Role.valueOf(role));
+                    }
+
+                    @Override
+                    public boolean isSecure() {
+                        return true;
+                    }
+
+                    @Override
+                    public String getAuthenticationScheme() {
+                        return AUTHENTICATION_SCHEME;
+                    }
+                });
+
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/User.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/User.java
new file mode 100644
index 0000000000000000000000000000000000000000..a18f358ebe052175de82944a4ba9f18e935b39b4
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/User.java
@@ -0,0 +1,64 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import lombok.*;
+import lombok.experimental.Delegate;
+import lombok.experimental.FieldDefaults;
+import lombok.extern.java.Log;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.*;
+
+@Log
+@FieldDefaults(level = AccessLevel.PRIVATE)
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(of = "email")
+public class User implements Principal {
+    UUID uuid = UUID.randomUUID();
+    String firstName, lastName, email;
+    byte[] passwordHash;
+    byte[] salt = new byte[16];
+
+    @Delegate
+    EnumSet<UserDatabase.Role> roles;
+
+    SecureRandom random = new SecureRandom();
+
+    @Builder
+    public User(String firstName, String lastName, String email, String password, EnumSet<UserDatabase.Role> roles)
+            throws NoSuchAlgorithmException, InvalidKeySpecException {
+        this.firstName = firstName;
+        this.lastName = lastName;
+        this.email = email;
+        this.roles = roles;
+
+        random.nextBytes(salt);
+        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
+        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+        passwordHash = factory.generateSecret(spec).getEncoded();
+    }
+
+    @Override
+    public String getName() {
+        return lastName + ", " + firstName+" <"+email+">";
+    }
+
+    public String toString() {
+        return email + "" + Base64.getEncoder().encodeToString(passwordHash);
+    }
+
+    public boolean checkPassword(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
+        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+        byte[] submittedPasswordHash = factory.generateSecret(spec).getEncoded();
+        return Arrays.equals(passwordHash, submittedPasswordHash);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/security/UserDatabase.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/UserDatabase.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e0cc79d4b46dc5011cbf5f295947d4e030f74b7
--- /dev/null
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/security/UserDatabase.java
@@ -0,0 +1,66 @@
+package fr.univtln.bruno.samples.jaxrs.security;
+
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+import lombok.ToString;
+import lombok.extern.java.Log;
+
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.*;
+
+@Log
+@ToString
+public class UserDatabase {
+    public static final UserDatabase USER_DATABASE = new UserDatabase();
+
+    // We need a signing key for the id token, so we'll create one just for this example. Usually
+    // the key would be read from your application configuration instead.
+    public static final Key KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
+
+    static {
+        try {
+            USER_DATABASE.addUser("John", "Doe", "john.doe@nowhere.com", "admin", EnumSet.of(Role.ADMIN));
+            USER_DATABASE.addUser("William", "Smith", "william.smith@here.net", "user", EnumSet.of(Role.USER));
+            USER_DATABASE.addUser("Mary", "Robert", "mary.roberts@here.net", "user", EnumSet.of(Role.USER));
+        } catch (InvalidKeySpecException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private final Map<String, User> users = new HashMap<>();
+
+    public static void main(String[] args) {
+        USER_DATABASE.users.values().forEach(u->log.info(u.toString()));
+    }
+
+    public void addUser(String firstname, String lastname, String email, String password, EnumSet<Role> roles)
+            throws InvalidKeySpecException, NoSuchAlgorithmException {
+        users.put(email, User.builder().firstName(firstname).lastName(lastname).email(email).password(password).roles(roles).build());
+    }
+
+    public Map<String, User> getUsers() {
+        return Collections.unmodifiableMap(users);
+    }
+
+    public void removeUser(String email) {
+        users.remove(email);
+    }
+
+    public boolean checkPassword(String email, String password) throws InvalidKeySpecException, NoSuchAlgorithmException {
+        return users.get(email).checkPassword(password);
+    }
+
+    public User getUser(String email) {
+        return users.get(email);
+    }
+
+    public Set<Role> getUserRoles(String email) {
+        return users.get(email).getRoles();
+    }
+
+    public enum Role {ADMIN, USER, GUEST}
+}
diff --git a/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java b/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java
index c830df7e2656868cdb1f153a31a62b2e1dcc6d55..5255f7995aba00a93ff64a21461e29119d1f3faa 100644
--- a/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java
+++ b/src/main/java/fr/univtln/bruno/samples/jaxrs/server/BiblioServer.java
@@ -18,25 +18,6 @@ public class BiblioServer {
 // Base URI the Grizzly HTTP server will listen on
     public static final String BASE_URI = "http://0.0.0.0:9998/myapp";
 
-    /**
-     * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
-     *
-     * @return Grizzly HTTP server.
-     */
-    public static HttpServer startServer() {
-        // create a resource config that scans for JAX-RS resources and providers
-        // in demos package and add a logging feature to the server.
-        Logger logger = Logger.getLogger(BiblioServer.class.getName());
-
-        final ResourceConfig rc = new ResourceConfig()
-                .packages(true, "fr.univtln.bruno.samples.jaxrs")
-                .register(new LoggingFeature(logger, Level.INFO, null, null));
-
-        // create and start a new instance of grizzly http server
-        // exposing the Jersey application at BASE_URI
-        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
-    }
-
     /**
      * Main method.
      *
@@ -50,10 +31,30 @@ public class BiblioServer {
         Runtime.getRuntime().addShutdownHook(new Thread(server::shutdownNow));
 
         log.info(String.format("Application started.%n" +
-                "Stop the application using CTRL+C"));
+                               "Stop the application using CTRL+C"));
 
         //We wait an infinite time.
         Thread.currentThread().join();
         server.shutdown();
     }
+
+    /**
+     * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
+     *
+     * @return Grizzly HTTP server.
+     */
+    public static HttpServer startServer() {
+        // create a resource config that scans for JAX-RS resources and providers
+        // in demos package and add a logging feature to the server.
+        Logger logger = Logger.getLogger(BiblioServer.class.getName());
+        logger.setLevel(Level.FINE);
+
+        final ResourceConfig rc = new ResourceConfig()
+                .packages(true, "fr.univtln.bruno.samples.jaxrs")
+                .register(new LoggingFeature(logger, Level.INFO, LoggingFeature.Verbosity.PAYLOAD_TEXT, null));
+
+        // create and start a new instance of grizzly http server
+        // exposing the Jersey application at BASE_URI
+        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
+    }
 }