diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f7c4ce5bc56f5b194d657b5e2c42e442b5f14d1b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+yarn.lock
+.vscode
+config.json
\ No newline at end of file
diff --git a/README.md b/README.md
index dad5fca12728ecc3dfdd944028561b65e3981619..b5fe36890ac97d64fc55681dcc380131404275e3 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,25 @@
-# RoleGame
\ No newline at end of file
+# RoleGame
+
+## Dependencies
+
+### Used
+* `express`: Fast, unopinionated, minimalist web framework
+* `bcrypt`: A bcrypt library for NodeJS.
+* `express-session`: Simple session middleware for Express
+* `pug`: A clean, whitespace-sensitive template language for writing HTML
+* `mongoose`: Mongoose MongoDB ODM
+* `body-parser`: Node.js body parsing middleware
+* `morgan`: HTTP request logger middleware for node.js
+
+### To use
+* `joi`: Object schema description language and validator for JavaScript objects.
+
+## Release
+
+### Next: v0.1.0
+* [ ] Authentication and session
+* [ ] Validate mongoose models
+* [ ] Make mongoose unique index work
+
+### Next: v0.2.0
+* [ ] Message handler
diff --git a/config.json.template b/config.json.template
new file mode 100644
index 0000000000000000000000000000000000000000..9b502de2b8b1236ffbde948bbf3e4e8450386fd5
--- /dev/null
+++ b/config.json.template
@@ -0,0 +1,5 @@
+{
+  "port": Number,
+  "secret": String,
+  "cryptRounds": Number
+}
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d307bc5d409eec01a6c3049a08337f6eff3090c6
--- /dev/null
+++ b/index.js
@@ -0,0 +1,82 @@
+const express = require('express');
+const session = require('express-session');
+const bodyParser = require('body-parser');
+const User = require('./models/user');
+const mongoose = require('mongoose');
+const bcrypt = require('bcrypt');
+const morgan = require('morgan');
+
+const config = require('./config.json');
+
+// Utils
+const render = (req, res, view, options) => res.render(view, {
+  ...options,
+  user: req.session.user,
+  nextUrl: req.url,
+});
+
+// Configuration
+const app = express();
+app.set('view engine', 'pug');
+app.use(morgan('tiny'));
+app.use(session({
+  secret: config.secret,
+  resave: false,
+  saveUninitialized: false
+}));
+
+// Middlewares
+app.use(bodyParser.urlencoded({
+  extended: false,
+}));
+app.use((req, res, next) => {
+  if (req.session.user || ['/', '/signup', '/login'].includes(req.url)) {
+    next();
+  } else {
+    return res.redirect('/signup');
+  }
+});
+
+app.get('/', (req, res) => {
+  return render(req, res, 'home');
+});
+app.get('/signup', (req, res) => {
+  return render(req, res, 'signup');
+});
+app.post('/signup', (req, res) => {
+  const passwordHash = bcrypt.hashSync(req.body.password, config.cryptRounds);
+  User.create(req.body, (err, user) => {
+    err ? console.error(err) : null;
+    user.passwordHash = passwordHash;
+    user.save();
+    req.session.user = user;
+    return res.redirect('/');
+  });
+});
+app.post('/login', (req, res) => {
+  User.findOne({ username: req.body.username }, (err, user) => {
+    err ? console.error(err) : null;
+    if (bcrypt.compareSync(req.body.password, user.passwordHash)) {
+      req.session.user = user;
+      return res.redirect(req.query.nextUrl || '/');
+    } else {
+      console.error("Bad authentication");
+      return res.redirect('/signup');
+    }
+  });
+});
+app.post('/logout', (req, res) => {
+  req.session.destroy();
+  return res.redirect('/');
+})
+
+mongoose.connect('mongodb://localhost/rolegame', err => {
+  if (err) {
+    console.error('ERROR Unable to connect to Mongo database')
+  } else {
+    console.log('Server connected to Mongo database');
+  }
+  app.listen(config.port, () => {
+    console.log(`Server listening on http://localhost:${config.port}`);
+  });
+});
diff --git a/models/character.js b/models/character.js
new file mode 100644
index 0000000000000000000000000000000000000000..95853d2b3d31cb6259b7101a57e0af77485c918a
--- /dev/null
+++ b/models/character.js
@@ -0,0 +1,8 @@
+const mongoose = require('mongoose');
+
+const Character = new mongoose.Schema({
+  name: String,
+  level: Number,
+});
+
+module.exports = mongoose.model('Character', Character);
\ No newline at end of file
diff --git a/models/user.js b/models/user.js
new file mode 100644
index 0000000000000000000000000000000000000000..fdb9dc2587a5453ea56b85e9a19e301f93f3c045
--- /dev/null
+++ b/models/user.js
@@ -0,0 +1,25 @@
+const mongoose = require('mongoose');
+
+const User = new mongoose.Schema({
+  firstName: {
+    type: String,
+    required: true,
+  },
+  lastName: {
+    type: String,
+  },
+  username: {
+    unique: true,
+    type: String,
+    lowercase: true
+  },
+  email: {
+    type: String,
+    required: true,
+  },
+  passwordHash: {
+    type: String,
+  },
+});
+
+module.exports = mongoose.model('User', User);
\ No newline at end of file
diff --git a/models/weapon.js b/models/weapon.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c74f2e8e7c46689a1d9ce16181ad26a970a2e96
--- /dev/null
+++ b/models/weapon.js
@@ -0,0 +1,8 @@
+const mongoose = require('mongoose');
+
+const Weapon = new mongoose.Schema({
+    name: String,
+    required_level: Number
+});
+
+module.exports = mongoose.model('Weapon', Weapon);
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e3b0f5265bcfe6b94893fabefb7e5623309b5744
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+  "scripts": {
+    "dev": "nodemon index.js"
+  },
+  "dependencies": {
+    "bcrypt": "^3.0.4",
+    "body-parser": "^1.18.3",
+    "eslint": "^5.13.0",
+    "express": "^4.16.4",
+    "express-session": "^1.15.6",
+    "mongoose": "^5.4.11",
+    "morgan": "^1.9.1",
+    "nodemon": "^1.18.10",
+    "pug": "^2.0.3"
+  }
+}
diff --git a/views/base.pug b/views/base.pug
new file mode 100644
index 0000000000000000000000000000000000000000..38855d3c86dc03a07458dd4ec5681663723f9595
--- /dev/null
+++ b/views/base.pug
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+html(lang="en")
+  head
+    meta(charset="UTF-8")
+    meta(name="viewport", content="width=device-width, initial-scale=1.0")
+    meta(http-equiv="X-UA-Compatible", content="ie=edge")
+    link(rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" integrity="sha256-9mbkOfVho3ZPXfM7W8sV2SndrGDuh7wuyLjtsWeTI1Q=" crossorigin="anonymous")
+    title RoleGame
+  body
+    block navbar
+      if !user
+        form.ui.form(action="/login", method="post")
+          .ui.pointing.menu
+            .right.menu
+              .item
+                .ui.input.transparent
+                  input#username(type="text" name="username" placeholder="username")
+              .item
+                .ui.transparent.input
+                  input#password(type="password" name="password" placeholder="password")
+              .item
+                .ui.transparent.input
+                  input.ui.button(type="submit" value="Se connecter")
+      else
+        form.ui.form(action="/logout", method="post")
+          .ui.pointing.menu
+            .right.menu
+              .item #{user.firstName} #{user.lastName}
+              .item
+                button.ui.icon.button.basic(type="submit")
+                  i.power.off.icon
+    .ui.container
+      block main
+    block script
+      script(src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E=" crossorigin="anonymous")
+      script(src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js" integrity="sha256-t8GepnyPmw9t+foMh3mKNvcorqNHamSKtKRxxpUEgFI=" crossorigin="anonymous")
\ No newline at end of file
diff --git a/views/home.pug b/views/home.pug
new file mode 100644
index 0000000000000000000000000000000000000000..c227ddd8f33b019c79860ce241c0298e9b527bbe
--- /dev/null
+++ b/views/home.pug
@@ -0,0 +1,4 @@
+extends base.pug
+
+block main
+  h1.ui.header Bienvenue sur RoleGame
diff --git a/views/signup.pug b/views/signup.pug
new file mode 100644
index 0000000000000000000000000000000000000000..afcd9076e903308f8f223e5feeec21b0c4b8e80c
--- /dev/null
+++ b/views/signup.pug
@@ -0,0 +1,22 @@
+extends base.pug
+
+block main
+  form.ui.form(action="/signup" method="post")
+    .two.fields
+      .field
+        label(for="firstName") Prénom
+        input#firstName(type="text", name="firstName")
+      .field
+        label(for="lastName") Nom de famille
+        input#lastName(type="text", name="lastName")
+    .field
+      label(for="email") Email
+      input#email(type="email", name="email")
+    .field
+      label(for="username") Nom d'utilisateur
+      input#username(type="text", name="username")
+    .field
+      label(for="password") Mot de passe
+      input#password(type="password", name="password")
+    .field
+      input.ui.button(type="submit", value="S'inscrire")
\ No newline at end of file