Node.js Express Firebase Admin SDK Server Side Authentication in Javascript Full Project

Node.js Express Firebase Admin SDK Server Side Authentication in Javascript Full Project

Welcome folks I am back with another blog post. In this post we will be talking about how to implement firebase server side authentication in Node.js using firebase admin sdk full project for beginners. All the source code is given in the description. A step by step youtube video is also shown below.

 

Screenshots

 

Source Code

 

const cookieParser = require("cookie-parser");
const csrf = require("csurf");
const bodyParser = require("body-parser");
const express = require("express");
const admin = require("firebase-admin");

const serviceAccount = require("./serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://aadharcardscanner-72071.firebaseio.com",
});

const csrfMiddleware = csrf({ cookie: true });

const PORT = process.env.PORT || 5000;
const app = express();

app.engine("html", require("ejs").renderFile);
app.use(express.static("static"));

app.use(bodyParser.json());
app.use(cookieParser());
app.use(csrfMiddleware);

app.all("*", (req, res, next) => {
  res.cookie("XSRF-TOKEN", req.csrfToken());
  next();
});

app.get("/login", function (req, res) {
  res.render("login.html");
});

app.get("/signup", function (req, res) {
  res.render("signup.html");
});

app.get("/profile", function (req, res) {
  const sessionCookie = req.cookies.session || "";

  admin
    .auth()
    .verifySessionCookie(sessionCookie, true /** checkRevoked */)
    .then(() => {
      res.render("profile.html");
    })
    .catch((error) => {
      res.redirect("/login");
    });
});

app.get("/", function (req, res) {
  res.render("index.html");
});

app.post("/sessionLogin", (req, res) => {
  const idToken = req.body.idToken.toString();

  const expiresIn = 60 * 60 * 24 * 5 * 1000;

  admin
    .auth()
    .createSessionCookie(idToken, { expiresIn })
    .then(
      (sessionCookie) => {
        const options = { maxAge: expiresIn, httpOnly: true };
        res.cookie("session", sessionCookie, options);
        res.end(JSON.stringify({ status: "success" }));
      },
      (error) => {
        res.status(401).send("UNAUTHORIZED REQUEST!");
      }
    );
});

app.get("/sessionLogout", (req, res) => {
  res.clearCookie("session");
  res.redirect("/login");
});

app.listen(PORT, () => {
  console.log(`Listening on http://localhost:${PORT}`);
});

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Home page</title>
  <link rel="stylesheet" href="./mvp.css" />
</head>
<body>
   <main> 
     <h1>Home page</h1>
     <p>This page is public</p>
     <a href="/profile">profile</a>
   </main>
</body>
</html>

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Firebase Server Auth</title>
    <link rel="stylesheet" href="./mvp.css" />
  </head>
  <body>
    <main>
      <section>
        <form id="signup">
          <label>Login</label>
          <input type="text" name="login" />
          <label>Password</label>
          <input type="password" name="password" />
          <button>Sign up</button>
        </form>
      </section>

      <script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"></script>
      <script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-auth.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/js-cookie@rc/dist/js.cookie.min.js"></script>

      <script>
        var firebaseConfig = {
            apiKey: "AIzaSyD5D4hc_-Idvb_nsTZBczhIcEn1jZsBLKo",
            authDomain: "aadharcardscanner-72071.firebaseapp.com",
            databaseURL: "https://aadharcardscanner-72071.firebaseio.com",
            projectId: "aadharcardscanner-72071",
            storageBucket: "aadharcardscanner-72071.appspot.com",
            messagingSenderId: "922187200582",
            appId: "1:922187200582:web:19c6ab71273f1ca88c3247",
          };
          // Initialize Firebase
          firebase.initializeApp(firebaseConfig);

          firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE)


        document
          .getElementById("signup")
          .addEventListener("submit", (event) => {
            event.preventDefault();
            const login = event.target.login.value;
            const password = event.target.password.value;

            firebase
              .auth()
              .createUserWithEmailAndPassword(login, password)
              .then(({ user }) => {
                return user.getIdToken().then((idToken) => {
                  return fetch("/sessionLogin", {
                    method: "POST",
                    headers: {
                      Accept: "application/json",
                      "Content-Type": "application/json",
                      "CSRF-Token": Cookies.get("XSRF-TOKEN"),
                    },
                    body: JSON.stringify({ idToken }),
                  });
                });
              })
              .then(() => {
                return firebase.auth().signOut();
              })
              .then(() => {
                window.location.assign("/profile");
              });
            return false;
          });
      </script>
    </main>
  </body>
</html>

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Firebase Server Auth</title>
    <link rel="stylesheet" href="./mvp.css" />
    <script
      src="https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"
      defer
    ></script>
    <script
      src="https://www.gstatic.com/firebasejs/7.14.1/firebase-auth.js"
      defer
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/js-cookie@rc/dist/js.cookie.min.js"
      defer
    ></script>
  </head>
  <body>
    <main>
      <section>
        <form id="login">
          <label>Login</label>
          <input type="text" name="login" />
          <label>Password</label>
          <input type="password" name="password" />
          <button>Log in</button>
        </form>
      </section>

      <script>
        window.addEventListener("DOMContentLoaded", () => {
          var firebaseConfig = {
            apiKey: "AIzaSyD5D4hc_-Idvb_nsTZBczhIcEn1jZsBLKo",
            authDomain: "aadharcardscanner-72071.firebaseapp.com",
            databaseURL: "https://aadharcardscanner-72071.firebaseio.com",
            projectId: "aadharcardscanner-72071",
            storageBucket: "aadharcardscanner-72071.appspot.com",
            messagingSenderId: "922187200582",
            appId: "1:922187200582:web:19c6ab71273f1ca88c3247",
          };
          // Initialize Firebase
          firebase.initializeApp(firebaseConfig);

          firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE)


          document
            .getElementById("login")
            .addEventListener("submit", (event) => {
                event.preventDefault();
              const login = event.target.login.value;
              const password = event.target.password.value;

              firebase
                .auth()
                .signInWithEmailAndPassword(login, password)
                .then(({ user }) => {
                  return user.getIdToken().then((idToken) => {
                    return fetch("/sessionLogin", {
                      method: "POST",
                      headers: {
                        Accept: "application/json",
                        "Content-Type": "application/json",
                        "CSRF-Token": Cookies.get("XSRF-TOKEN"),
                      },
                      body: JSON.stringify({ idToken }),
                    });
                  });
                })
                .then(() => {
                  return firebase.auth().signOut();
                })
                .then(() => {
                  window.location.assign("/profile");
                });
              return false;
            });

    
        });
      </script>
    </main>
  </body>
</html>

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Profile page</title>
  <link rel="stylesheet" href="./mvp.css" />
</head>
<body>
   <main> 
     <h1>Profile page</h1>
     <p>This page is private</p>
     <a href="/sessionLogout">Log out</a>
   </main>
</body>
</html/>

 

/* MVP.css v1.5 - https://github.com/andybrewer/mvp */

:root {
    --border-radius: 5px;
    --box-shadow: 2px 2px 10px;
    --color: #118bee;
    --color-accent: #118bee0b;
    --color-bg: #fff;
    --color-bg-secondary: #e9e9e9;
    --color-secondary: #920de9;
    --color-secondary-accent: #920de90b;
    --color-shadow: #f4f4f4;
    --color-text: #000;
    --color-text-secondary: #999;
    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
    --hover-brightness: 1.2;
    --justify-important: center;
    --justify-normal: left;
    --line-height: 150%;
    --width-card: 285px;
    --width-card-medium: 460px;
    --width-card-wide: 800px;
    --width-content: 1080px;
  }
  
  /*
  @media (prefers-color-scheme: dark) {
    :root {
        --color: #0097fc;
        --color-accent: #0097fc4f;
        --color-bg: #333;
        --color-bg-secondary: #555;
        --color-secondary: #e20de9;
        --color-secondary-accent: #e20de94f;
        --color-shadow: #bbbbbb20;
        --color-text: #f7f7f7;
        --color-text-secondary: #aaa;
    }
  }
  */
  
  /* Layout */
  article aside {
    background: var(--color-secondary-accent);
    border-left: 4px solid var(--color-secondary);
    padding: 0.01rem 0.8rem;
  }
  
  body {
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font);
    line-height: var(--line-height);
    margin: 0;
    overflow-x: hidden;
    padding: 1rem 0;
  }
  
  footer,
  header,
  main {
    margin: 0 auto;
    max-width: var(--width-content);
    padding: 2rem 1rem;
  }
  
  hr {
    background-color: var(--color-bg-secondary);
    border: none;
    height: 1px;
    margin: 4rem 0;
  }
  
  section {
    display: flex;
    flex-wrap: wrap;
    justify-content: var(--justify-important);
  }
  
  section aside {
    border: 1px solid var(--color-bg-secondary);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow) var(--color-shadow);
    margin: 1rem;
    padding: 1.25rem;
    width: var(--width-card);
  }
  
  section aside:hover {
    box-shadow: var(--box-shadow) var(--color-bg-secondary);
  }
  
  section aside img {
    max-width: 100%;
  }
  
  /* Headers */
  article header,
  div header,
  main header {
    padding-top: 0;
  }
  
  header {
    text-align: var(--justify-important);
  }
  
  header a b,
  header a em,
  header a i,
  header a strong {
    margin-left: 0.5rem;
    margin-right: 0.5rem;
  }
  
  header nav img {
    margin: 1rem 0;
  }
  
  section header {
    padding-top: 0;
    width: 100%;
  }
  
  /* Nav */
  nav {
    align-items: center;
    display: flex;
    font-weight: bold;
    justify-content: space-between;
    margin-bottom: 7rem;
  }
  
  nav ul {
    list-style: none;
    padding: 0;
  }
  
  nav ul li {
    display: inline-block;
    margin: 0 0.5rem;
    position: relative;
    text-align: left;
  }
  
  /* Nav Dropdown */
  nav ul li:hover ul {
    display: block;
  }
  
  nav ul li ul {
    background: var(--color-bg);
    border: 1px solid var(--color-bg-secondary);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow) var(--color-shadow);
    display: none;
    height: auto;
    padding: .5rem 1rem;
    position: absolute;
    right: 0;
    top: 1.7rem;
    width: auto;
  }
  
  nav ul li ul li,
  nav ul li ul li a {
    display: block;
  }
  
  /* Typography */
  code,
  samp {
    background-color: var(--color-accent);
    border-radius: var(--border-radius);
    color: var(--color-text);
    display: inline-block;
    margin: 0 0.1rem;
    padding: 0rem 0.5rem;
    text-align: var(--justify-normal);
  }
  
  details {
    margin: 1.3rem 0;
  }
  
  details summary {
    font-weight: bold;
    cursor: pointer;
  }
  
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    line-height: var(--line-height);
  }
  
  mark {
    padding: 0.1rem;
  }
  
  ol li,
  ul li {
    padding: 0.2rem 0;
  }
  
  p {
    margin: 0.75rem 0;
    padding: 0;
  }
  
  pre {
    margin: 1rem 0;
    max-width: var(--width-card-wide);
    white-space: pre-line;
  }
  
  pre code,
  pre samp {
    padding: 1rem 2rem;
  }
  
  small {
    color: var(--color-text-secondary);
  }
  
  sup {
    background-color: var(--color-secondary);
    border-radius: var(--border-radius);
    color: var(--color-bg);
    font-size: xx-small;
    font-weight: bold;
    margin: 0.2rem;
    padding: 0.2rem 0.3rem;
    position: relative;
    top: -2px;
  }
  
  /* Links */
  a {
    color: var(--color-secondary);
    display: inline-block;
    font-weight: bold;
    text-decoration: none;
  }
  
  a:hover {
    filter: brightness(var(--hover-brightness));
    text-decoration: underline;
  }
  
  a b,
  a em,
  a i,
  a strong,
  button {
    border-radius: var(--border-radius);
    display: inline-block;
    font-size: medium;
    font-weight: bold;
    line-height: var(--line-height);
    margin: 0.5rem 0;
    padding: 1rem 2rem;
  }
  
  button {
    font-family: var(--font);
  }
  
  button:hover {
    cursor: pointer;
    filter: brightness(var(--hover-brightness));
  }
  
  a b,
  a strong,
  button {
    background-color: var(--color);
    border: 2px solid var(--color);
    color: var(--color-bg);
  }
  
  a em,
  a i {
    border: 2px solid var(--color);
    border-radius: var(--border-radius);
    color: var(--color);
    display: inline-block;
    padding: 1rem 2rem;
  }
  
  /* Images */
  figure {
    margin: 0;
    padding: 0;
  }
  
  figure img {
    max-width: 100%;
  }
  
  figure figcaption {
    color: var(--color-text-secondary);
  }
  
  /* Forms */
  
  button:disabled,
  input:disabled {
    background: var(--color-bg-secondary);
    border-color: var(--color-bg-secondary);
    color: var(--color-text-secondary);
    cursor: not-allowed;
  }
  
  button[disabled]:hover {
    filter: none;
  }
  
  form {
    border: 1px solid var(--color-bg-secondary);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow) var(--color-shadow);
    display: block;
    max-width: var(--width-card-wide);
    min-width: var(--width-card);
    padding: 1.5rem;
    text-align: var(--justify-normal);
  }
  
  form header {
    margin: 1.5rem 0;
    padding: 1.5rem 0;
  }
  
  input,
  label,
  select,
  textarea {
    display: block;
    font-size: inherit;
    max-width: var(--width-card-wide);
  }
  
  input[type="checkbox"],
  input[type="radio"] {
    display: inline-block;
  }
  
  input[type="checkbox"]+label,
  input[type="radio"]+label {
    display: inline-block;
    font-weight: normal;
    position: relative;
    top: 1px;
  }
  
  input,
  select,
  textarea {
    border: 1px solid var(--color-bg-secondary);
    border-radius: var(--border-radius);
    margin-bottom: 1rem;
    padding: 0.4rem 0.8rem;
  }
  
  input[readonly],
  textarea[readonly] {
    background-color: var(--color-bg-secondary);
  }
  
  label {
    font-weight: bold;
    margin-bottom: 0.2rem;
  }
  
  /* Tables */
  table {
    border: 1px solid var(--color-bg-secondary);
    border-radius: var(--border-radius);
    border-spacing: 0;
    overflow-x: scroll;
    overflow-y: hidden;
    padding: 0;
  }
  
  table td,
  table th,
  table tr {
    padding: 0.4rem 0.8rem;
    text-align: var(--justify-important);
  }
  
  table thead {
    background-color: var(--color);
    border-collapse: collapse;
    border-radius: var(--border-radius);
    color: var(--color-bg);
    margin: 0;
    padding: 0;
  }
  
  table thead th:first-child {
    border-top-left-radius: var(--border-radius);
  }
  
  table thead th:last-child {
    border-top-right-radius: var(--border-radius);
  }
  
  table thead th:first-child,
  table tr td:first-child {
    text-align: var(--justify-normal);
  }
  
  /* Quotes */
  blockquote {
    display: block;
    font-size: x-large;
    line-height: var(--line-height);
    margin: 1rem auto;
    max-width: var(--width-card-medium);
    padding: 1.5rem 1rem;
    text-align: var(--justify-important);
  }
  
  blockquote footer {
    color: var(--color-text-secondary);
    display: block;
    font-size: small;
    line-height: var(--line-height);
    padding: 1.5rem 0;
  }
  
  /* Custom styles */

Leave a Reply