Professional Documents
Culture Documents
Full Stack-Unit-Iii
Full Stack-Unit-Iii
Full Stack-Unit-Iii
Traditional RDBMS uses SQL syntax to store and retrieve data for further insights.
Instead, a NoSQL database system encompasses a wide range of database
technologies that can store structured, semi-structured, unstructured and polymorphic
data. Let’s understand about NoSQL with a diagram in this NoSQL database tutorial:
In this NoSQL tutorial for beginners, you will learn NoSQL basics like:
What is NoSQL?
Why NoSQL?
Brief History of NoSQL Databases
Features of NoSQL
Types of NoSQL Databases
Query Mechanism tools for NoSQL
What is the CAP Theorem?
Eventual Consistency
Advantages of NoSQL
Disadvantages of NoSQL
Why NoSQL?
The concept of NoSQL databases became popular with Internet giants like Google,
Facebook, Amazon, etc. who deal with huge volumes of data. The system response time
becomes slow when you use RDBMS for massive volumes of data.
To resolve this problem, we could “scale up” our systems by upgrading our existing
hardware. This process is expensive.
The alternative for this issue is to distribute database load on multiple hosts whenever
the load increases. This method is known as “scaling out.”
Features of NoSQL
Non-relational
Schema-free
NoSQL is Schema-Free
Simple API
Offers easy to use interfaces for storage and querying data provided
APIs allow low-level data manipulation & selection methods
Text-based protocols mostly used with HTTP REST with JSON
Mostly used no standard based NoSQL query language
Web-enabled databases running as internet-facing services
Distributed
Key-value pair storage databases store data as a hash table where each key is unique,
and the value can be a JSON, BLOB(Binary Large Objects), string, etc.
For example, a key-value pair may contain a key like “Website” associated with a value
like “Guru99”.
It is one of the most basic NoSQL database example. This kind of NoSQL database is
used as a collection, dictionaries, associative arrays, etc. Key value stores help the
developer to store schema-less data. They work best for shopping cart contents.
Redis, Dynamo, Riak are some NoSQL examples of key-value store DataBases. They
are all based on Amazon’s Dynamo paper.
Column-based
Column-oriented databases work on columns and are based on BigTable paper by
Google. Every column is treated separately. Values of single column databases are
stored contiguously.
They deliver high performance on aggregation queries like SUM, COUNT, AVG, MIN
etc. as the data is readily available in a column.
HBase, Cassandra, HBase, Hypertable are NoSQL query examples of column based
database.
Document-Oriented:
Document-Oriented NoSQL DB stores and retrieves data as a key value pair but the
value part is stored as a document. The document is stored in JSON or XML formats.
The value is understood by the DB and can be queried.
Relational Vs. Document
In this diagram on your left you can see we have rows and columns, and in the right, we
have a document database which has a similar structure to JSON. Now for the relational
database, you have to know what columns you have and so on. However, for a
document database, you have data store like JSON object. You do not require to define
which make it flexible.
The document type is mostly used for CMS systems, blogging platforms, real-time
analytics & e-commerce applications. It should not use for complex transactions which
require multiple operations or queries against varying aggregate structures.
Amazon SimpleDB, CouchDB, MongoDB, Riak, Lotus Notes, MongoDB, are popular
Document originated DBMS systems.
Graph-Based
A graph type database stores entities as well the relations amongst those entities. The
entity is stored as a node with the relationship as edges. An edge gives a relationship
between nodes. Every node and edge has a unique identifier.
OVERVIEW OF MONGO DB
Like any other database management language, MongoDB is based on a NoSQL database
that is used for storing data in a key-value pair. Its working is based on the concept of
document and collection. It is also an open-source, a document-oriented, cross-platform
database system that is written using C++. In this chapter, you will learn more about
MongoDB and its importance.
Mongo DB can be defined as a document-oriented database system that uses the concept of
NoSQL. It also provides high availability, high performance, along with automatic scaling.
This open-source product was developed by the company - 10gen in October 2007, and the
company also maintains it. MongoDB exists under the General Public License (GPL) as a
free database management tool as well as available under Commercial license as of the
manufacturer. MongoDB was also intended to function with commodity servers. Companies
of different sizes all over the world across all industries are using MongoDB as their
database.
Here are some key terminologies that you must know to get into the in-depth of MongoDB:
What is a Database?
In MongoDB, a database can be defined as a physical container for collections of data. Here,
on the file system, every database has its collection of files residing. Usually, a MongoDB
server contains numerous databases.
What is a Document?
A document can be defined as a collection of key-value pairs that contain dynamic schema.
Dynamic schema is something that documents of the equal collection do not require for
having the same collection of fields or construction, and a common field is capable of holding
various types of data.
Here is a table showing the relation between the terminologies used in RDBMS and MongoDB:
RDBMS MongoDB
Database Database
Table Collection
Column Field
Adobe
McAfee
LinkedIn
FourSquare
MetLife
eBay
SAP
Document-Oriented data storage, i.e., data, is stored in a JSON style format, which increases
the readability of data as well.
Replication and high availability of data.
MongoDB provides Auto-sharding.
Ad hoc queries are supported by MongoDB, which helps in searching by range queries, field,
or using regex terms.
Indexing of values can be used to create and improve the overall search performance in
MongoDB. MongoDB allows any field to be indexed within a document.
MongoDB has a rich collection of queries.
Updating of data can be done at a faster pace.
It can be integrated with other popular programming languages also to handle structured as
well as unstructured data within various types of applications.
db.inventory.insertMany([
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);
MongoDB Shell
db.inventory.find( {} )
MongoDB Shell
The following example selects from the inventory collection all documents where
the status equals "D" :
MongoDB Shell
NOTE
The MongoDB Compass query bar autocompletes the current query based on the
keys in your collection's documents, including keys in embedded sub-documents.
Operators
A query filter document can use the query operators to specify conditions in the following
form:
MongoDB Shell
The following example retrieves all documents from the inventory collection
where status equals either "A" or "D" :
MongoDB Shell
NOTE
Although you can express this query using the $or operator, use the $in operator
rather than the $or operator when performing equality checks on the same field.
The following example retrieves all documents in the inventory collection where
the status equals "A" and qty is less than ( $lt ) 30 :
MongoDB Shell
Specify OR Conditions
Using the $or operator, you can specify a compound query that joins each clause with a
logical OR conjunction so that the query selects the documents in the collection that match at
least one condition.
MongoDB Shell
NOTE
In the following example, the compound query document selects all documents in the
collection where the status equals "A" and either qty is less than ( $lt ) 30 or item starts
with the character p :
db.inventory.find( {
status: "A",
})
MongoDB Shell
SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
NOTE
// Parse JSON bodies for this app. Make sure you put
// `app.use(express.json())` **before** your route handlers!
app.use(express.json());
Common Gotchas
If the JSON body is malformed, Express will error out with an
HTTP 400. This error also triggers error handling middleware.
res.data; // { answer: 42 }
Files
Neither Express nor body-parser supports file uploads out of the
box. However, you can use the Formidable module on npm to
handle file uploads. You can learn how on our tutorial on file
uploads with Express.
Espresso supports:
Use Node.js? Want to learn MongoDB? This is the blog series for you!
In this Quick Start series, I’ll walk you through the basics of how to get
started using MongoDB with Node.js. In today’s post, we’ll work
through connecting to a MongoDB database from a Node.js script,
retrieving a list of databases, and printing the results to your console.
Prefer to learn by video? I've got ya covered. Check out the video
below that covers how to get connected as well as how to perform the
CRUD operations.
Set up
Before we begin, we need to ensure you’ve completed a few
prerequisite steps.
Install Node.js
First, make sure you have a supported version of Node.js installed. The
current version of MongoDB Node.js Driver requires Node 4.x or
greater. For these examples, I've used Node.js 14.15.4. See
the MongoDB Compatability docs for more information on which
version of Node.js is required for each version of the Node.js driver.
Head over to Atlas and create a new cluster in the free tier. At a high
level, a cluster is a set of nodes where copies of your database will be
stored. Once your tier is created, load the sample data. If you're not
familiar with how to create a new cluster and load the sample data,
check out this video tutorial from MongoDB Developer
Advocate Maxime Beugnet.
Get started with an M0 cluster on Atlas today. It's free forever, and
it's the easiest way to try out the steps in this blog series.
The Wizard will prompt you to add your current IP address to the IP
Access List and create a MongoDB user if you haven't already done so.
Be sure to note the username and password you use for the new
MongoDB user as you'll need them in a later step.
Import MongoClient
The MongoDB module exports MongoClient, and that’s what we’ll use to
connect to a MongoDB database. We can use an instance of
MongoClient to connect to a cluster, access the database in that
cluster, and close the connection to that cluster.
const {MongoClient} = require('mongodb');
Note: the username and password you provide in the connection string
are NOT the same as your Atlas credentials.
/**
* Connection URI. Update <username>, <password>, and <your-cluster-url> to
reflect your cluster.
* See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
*/
const uri = "mongodb+srv://<username>:<password>@<your-cluster-url>/test?
retryWrites=true&w=majority";
Now we are ready to interact with our database. Let's build a function
that prints the names of the databases in this cluster. It's often useful
to contain this logic in well named functions in order to improve the
readability of your codebase. Throughout this series, we'll create new
functions similar to the function we're creating here as we learn how
to write different types of queries. For now, let's call a function
named listDatabases().
await listDatabases(client);
Let’s wrap our calls to functions that interact with the database in
a try/catch statement so that we handle any unexpected errors.
try {
await client.connect();
await listDatabases(client);
} catch (e) {
console.error(e);
}
Once we have our main() function written, we need to call it. Let’s send
the errors to the console.
main().catch(console.error);
Putting it all together, our main() function and our call to it will look
something like the following.
async function main(){
/**
* Connection URI. Update <username>, <password>, and <your-cluster-url>
to reflect your cluster.
* See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
*/
const uri =
"mongodb+srv://<username>:<password>@<your-cluster-url>/test?
retryWrites=true&w=majority";
try {
// Connect to the MongoDB cluster
await client.connect();
} catch (e) {
console.error(e);
} finally {
await client.close();
}
}
main().catch(console.error);
This function will retrieve a list of databases in our cluster and print
the results in the console.
async function listDatabases(client){
databasesList = await client.db().admin().listDatabases();
console.log("Databases:");
databasesList.databases.forEach(db => console.log(` - ${db.name}`));
};
What’s next?
Today, you were able to connect to a MongoDB database from a
Node.js script, retrieve a list of databases in your cluster, and view the
results in your console. Nice!
mkdir my-app
cd my-app
npm init -y
Recommended:-Insert Data into MongoDB Using Node.js
Step 2 – Install express flash ejs body-parser mongoose Modules
npm install
Create database.js file into your app root directory and add the
following code into it to connect your app to the mongodb database:
2 mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser:
true});
3
var conn = mongoose.connection;
4 conn.on('connected', function() {
6 });
7 conn.on('disconnected',function(){
9 })
module.exports = conn;
11
1
const mongoose = require("../database");
2
3 // create an schema
5 name: String,
6 email:String
7 });
8
var userModel=mongoose.model('users',userSchema);
9
10
module.exports = mongoose.model("Users", userModel);
11
Create routes; so visit routes directory and open users.js route file;
Then add the following routes into it:
6
/* GET home page. */
7
router.get('/', function(req, res, next) {
8
9
userModel.find((err, docs) => {
10
if (!err) {
11
res.render("list", {
12
data: docs
13
});
14 } else {
19
});
20 module.exports = router;
21
1 <!DOCTYPE html>
2 <html>
<head>
3
<title>fetch data from mongodb using node js and display in html</title>
4
<link rel='stylesheet' href='/stylesheets/style.css' />
5
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
6
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
7
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
8
crossorigin="anonymous"></script>
9 <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
10 rel="stylesheet" integrity="sha384-MCw98/
11SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
12</head>
13<body>
<div>
14
<a href="/customers" class="btn btn-info ml-3">Fetch data from mongodb using node
15
</div>
16
<!-- <% if (messages.error) { %>
17
<p style="color:red"><%- messages.error %></p>
18
<% } %> -->
19
22<% } %>
23<br>
24 <table class="table">
<thead>
25
<tr>
26
<th scope="col">#</th>
27
<th scope="col">Name</th>
28
<th scope="col">Email</th>
29
30
</tr>
31</thead>
32<tbody>
33 <% if(data.length){
34
36 <tr>
43 }else{ %>
<tr>
44
<td colspan="3">No user</td>
45
</tr>
46
<% } %>
47
48
</tbody>
49
</table>
50</body>
51</html>
13 app.use(logger('dev'));
14 app.use(express.json());
app.use(cookieParser());
16
17 app.use(express.static(path.join(__dirname, 'public')));
18
19 app.use(session({
secret: '123456catr',
20
resave: false,
21
saveUninitialized: true,
22
cookie: { maxAge: 60000 }
23
}))
24
25
app.use(flash());
26 app.use('/list', usersRouter);
27
30 next(createError(404));
});
31
32
// error handler
33
app.use(function(err, req, res, next) {
34
// set locals, only providing error in development
35
res.locals.message = err.message;
36
res.locals.error = req.app.get('env') === 'development' ? err : {};
37
39 res.status(err.status || 500);
40 res.render('error');
41 });
42
43 // port must be set to 3000 because incoming http requests are routed from port 80
port 8080
44
app.listen(3000, function () {
45 console.log('Node app is running on port 3000');
46
47
48
49
module.exports = app;
50
51
You can use the following command to start node js app server:
npm start
http://127.0.0.1:3000/list
Conclusion
Fetch data from mongodb in node js express using mongoose express
app; In this tutorial, you have learned how to fetch and display data in
html list form mongoDB database using mongoose node js express app.
I want to be able to set a single cookie, and read that single cookie with each request made to the nodejs server
instance. Can it be done in a few lines of code, without the need to pull in a third party lib?
Cookies are small data that are stored on a client side and sent to the client along with
server requests. Cookies have various functionality, they can be used for maintaining
sessions and adding user-specific features in your web app. For this, we will use cookie-
parser module of npm which provides middleware for parsing of cookies.
First set your directory of the command prompt to root folder of the project and run the
following command:
npm init
This will ask you details about your app and finally will create a package.json file.
After that run the following command and it will install the required module and add them in
your package.json file
npm install express cookie-parser --save
package.json file looks like this :
After that we will setup basic express app by writing following code in our app.js file in root
directory .
});
app.listen(3000, (err)=>{
if(err)
throw err;
});
So until now we have successfully set up our express app now let’s start with cookies.
For cookies first, we need to import the module in our app.js file and use it like other
middlewares.
Let’s say we have a user and we want to add that user data in the cookie then we have to
add that cookie to the response using the following code :
res.cookie(name_of_cookie, value_of_cookie);
This can be explained by the following example :
app.use(cookieParser());
});
name : "Ritik",
Age : "18"
res.cookie("userData", users);
});
res.send(req.cookies);
});
app.listen(3000, (err)=>{
if(err)
throw err;
});
So if we restart our server and make a get request to the route: localhost:3000/getuser
before setting the cookies it is as follows :
After making a request to localhost:3000/setuser it will add user data to cookie and gives
output as follows :
If we have multiple objects pushed in cookies then we can access specific cookie
using req.cookie.cookie_name .
Adding Cookie with expiration Time
We can add a cookie with some expiration time i.e. after that time cookies will be
destroyed automatically. For this, we need to pass an extra property to the res.cookie
object while setting the cookies.
It can be done by using any of the two ways :
app.use(cookieParser());
});
let users = {
name : "Ritik",
Age : "18"
res.cookie("userData", users);
});
res.send(req.cookies);
});
res.clearCookie('userData');
});
app.listen(3000, (err)=>{
if(err)
throw err;
});
HANDLING USER AUTHENTICATION WITH NODEJS
how to secure a Node.js web application built with the Express framework
by implementing user authentication. You'll enhance a starter Node.js
project to practice the following security concepts:
This guide uses the Auth0 Express OpenID Connect library to secure
Express web applications. This library provides Node.js developers with an
alternative to Passport.js. Express OpenID Connect lets you add user
authentication to Express applications using security best practices while
writing less code.
With the help of Auth0, you don't need to be an expert on identity protocols,
such as OAuth 2.0 or OpenID Connect, to understand how to secure your
web application stack. You first integrate your application with Auth0. Your
application will then redirect users to an Auth0 customizable login page
when they need to log in. Once your users log in successfully, Auth0 takes
them back to your app, returning JSON Web Tokens (JWTs) with their
authentication and user information.
If you are short of time, check out the Auth0 Express Quickstart to get up
and running with user authentication for Express in just a few minutes.
You can emulate the live reload behavior of front-end frameworks such
as React and Angular in Express templates using Browsersync. The
browser will refresh automatically whenever the source code changes: for
example, when you modify a CSS rule or change the return value of a
function.
🛠 Open a separate terminal window and execute the following command to
serve the user interface of your Express app:
npm run ui
During the sign-up process, you create something called an Auth0 Tenant,
representing the product or service to which you are adding authentication.
🛠 Once you sign in, Auth0 takes you to the Dashboard. In the left sidebar
menu, click on "Applications".
🛠 Then, click the "Create Application" button. A modal opens up with a form
to provide a name for the application and choose its type.
Name:
Auth0 Express Sample
🛠 Click the "Create" button to complete the process. Your Auth0 application
page loads up.
In the next step, you'll learn how to help Express and Auth0 communicate.
When you use Auth0, you don't have to build login forms. Auth0 offers
a Universal Login page to reduce the overhead of adding and managing
authentication.
How does Universal Login work?
Your Express application will redirect users to Auth0 whenever they trigger
an authentication request. Auth0 will present them with a login page. Once
they log in, Auth0 will redirect them back to your Express application. For
that redirecting to happen securely, you must specify in your Auth0
Application Settings the URLs to which Auth0 can redirect users once it
authenticates them.
🛠 As such, click on the "Settings" tab of your Auth0 Application page and fill
in the following values:
The above value is the URL that Auth0 can use to redirect your users after
they successfully log in.
The above value is the URL that Auth0 can use to redirect your users after
they log out.
🛠 Do not close this page yet. You'll need some of its information in the next
section.
From the Auth0 Application Settings page, you need the Auth0 Domain and
Client ID values to allow your Express application to use the communication
bridge you created.
🛠 Open the .env file from your auth0-express-pug-sample project directory and
update it as follows:
DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=https://<AUTH0_DOMAIN>/
AUTH0_CLIENT_ID=
Feel free to dive deeper into the Auth0 Documentation to learn more about
how Auth0 helps you save time on implementing and managing identity.
🛠 Open the .env file once again and add a BASE_URL and SESSION_SECRET value
to it:
DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=<...>
AUTH0_CLIENT_ID=<...>
BASE_URL=http://localhost:4040
SESSION_SECRET=
The SESSION_SECRET value is the secret used to sign the session ID cookie,
which can be either a string for a single secret or an array of multiple
secrets.
Execute the following command to generate a suitable string for the session
secret:
node -e "console.log(crypto.randomBytes(32).toString('hex'))"
Copy and paste the output of the command above as the value
for SESSION_SECRET in .env.
For your application to recognize these new environment variables, you
need to restart the Node.js server. Locate the terminal window where you
executed npm run dev earlier, stop it, and run it again.
If users want to enter a protected route from your application, Auth0 will stop
them and ask them to present their credentials. If Auth0 can verify who they
are and that they are supposed to go in there, Auth0 will let them in.
Otherwise, Auth0 will take them back to a public application route.
Now, it's important to reiterate that the authentication process won't happen
within your application layer. Your Express application will redirect your
users to the Auth0 Universal Login page, where Auth0 asks for credentials
and redirects the user back to your application with the result of the
authentication process.
The Express OpenID Connect library provides the auth router to attach
authentication routes to your application. You won't have to
implement /login or /logout controllers, Express OpenID Connect takes does
that for you.
/**
* Required External Modules
*/
🛠 Then, update the App Configuration section to initialize and use auth as an
Express middleware function:
// src/index.js
/**
* App Configuration
*/
You are adding two additional properties, authRequired and auth0Logout. What
are these properties doing?
auth0Logout is another boolean value that enables the Auth0 logout feature,
which lets you log out a user of the Auth0 session. When implementing
logout functionality in an application, there are typically three sessions
layers you need to consider:
For example, if one of your users logged in using Google, you can configure
your Auth0 authentication service to log out the user from the application,
from the Auth0 session, or from Google itself. Check out the "Logout"
document to learn more details about the architecture of user logout.
For this application, you'll log out users from the Auth0 session layer.
The Express OpenID Connect library is all set up. You are ready to
implement user authentication in the next section.
Under the hood, Express OpenID Connect created a /login route for your
Express application. When the user clicks on this button, your Express
application will prompt the user to authenticate and provide consent for your
Express application to access certain data on behalf of that user. In your
current architecture, this means that your Express application redirects the
user to the Auth0 Universal Login page to carry out the authentication
process. You'll see this in action in the next sections.
You can make users land directly on a sign-up page instead of a login page
by creating a /sign-up route controller.
🛠 To start, open the src/index.js file. Locate the Routes Definitions section.
Under this section, there are different subsections that define routes for
each feature of your Expres web application. Locate
the > Authentication subsection, and update it as follows:
// src/index.js
/**
* Routes Definitions
*/
// > Authentication
You can pass new values to change what the Auth0 authorization server
returns depending on your use case. In your /sign-up controller, you specify
the screen_hint=signup property as an authorization parameter to take the
users to a sign-up form.
{
authorizationParams: {
screen_hint: "signup",
},
}
Now, create a sign-up button to trigger this event by requesting the /sign-
up route.
mixin signup-button()
button(
class="btn btn-primary btn-block",
onclick="window.location='/sign-up'"
) Sign Up
Using the Signup feature requires you to enable the Auth0 New Universal
Login Experience in your tenant.
🛠 Open the Universal Login section of the Auth0 Dashboard and choose the
"New" option under the "Experience" subsection.
🛠 Scroll down and click on the "Save Changes" button.
The difference between the log-in and sign-up user experience will be more
evident once you integrate those components with your Express application
and see them in action. You'll do that in the next sections.
mixin authentication-button(isAuthenticated)
if isAuthenticated
+logout-button
else
+login-button
You can build extensible interfaces. You can easily swap the login-
button mixin with the signup-button mixin in authentication-button to create a
"sign up/log out" switch. You could also wrap the "sign up/log out" switch in
a new-authentication-button mixin.
mixin auth-nav(isAuthenticated)
div(class="navbar-nav ml-auto")
+authentication-button(isAuthenticated)
mixin nav-bar(activeRoute)
div(class="nav-container mb-3")
nav(class="navbar navbar-expand-md navbar-light bg-light")
div(class="container")
div(class="navbar-brand logo")
+main-nav(activeRoute)
+auth-nav(isAuthenticated)
Once again, isAuthenticated shows up. The Express OpenID Connect library
defines this value in the req.oidc.isAuthenticated() method. Its return value is
essential for authentication to work correctly in your Express app.
In Express web applications, you have access to a one-way data flow from
route controller to template. As such, each route controller that renders a
template that depends on isAuthenticated must pass down this value.
/**
* App Configuration
*/
app.use(
auth({
issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.AUTH0_CLIENT_ID,
secret: process.env.SESSION_SECRET,
authRequired: false,
auth0Logout: true,
}),
);
You define res.locals within a middleware function handler. This object lets
you pass data around your Express application. All of your Pug templates
can access its properties (such as isAuthenticated) directly.
Since req.oidc.isAuthenticated() is a method, you have to execute it to get its
value.
There is one caveat about using res.locals: these values only live within an
individual request. As soon as the request-response cycle is complete, the
values are gone. This isn't a problem for your application since each time a
user requests a route from the browser, the request-response cycle starts all
over again.
🛠 Go ahead and try to log in. Your Express application redirects you to the
Auth0 Universal Login page. You can use a form to log in with a username
and password or a social identity provider like Google. Notice that this login
page also gives you the option to sign up.
Experiment: Use the signup-button mixin
You can customize the appearance of New Universal Login pages. You can
also override any text in the New Experience using the Text Customization
API.
🛠 Click on the Profile tab and then click on the "Log Out" button.
Notice that Express logged you out, but instead of taking you back to
the /profile route, it took you back to the / route, the home page.
🛠 Click on the Profile tab and now click on the "Log In" button.
This time, Express takes you again back to the home page, / after you log
in. As a user, you would expect to access the /profile page after you log in,
right? After all, your authentication system is acting like a bouncer. The
bouncer doesn't take people back to the nightclub entrance after they
present their ID. The bouncer lets them pass through and access the VIP
lounge or whatever room the bouncer is protecting.
This Express web app is using static routes to render its user interface. You
map a user interface action with a server endpoint or controller. This
mapping is hard-coded so far.
The /login route controller that the Express OpenID Connect library created
for you has a hard-coded value for the path to which Auth0 should return
users after they log in. That default value is the root of your server URL, /.
However, what if the /profile page had both public and protected
resources? In a scenario like that, anyone can visit the /profile page to read
its public information. Then, users can log in to read protected information.
The best user experience is for the users to return to the /profile page after
they log in, not the home page.
One way to fix this home-page redirect is to create a dedicated route for
each type of login and logout:
GET /sign-up-profile
GET /sign-up-external-api
GET /login-profile
GET /login-external-api
GET /logout-profile
GET /logout-external-api
However, this method won't scale well at all. Imagine if you had more than
10 different pages that require that smooth login experience.
It would be better to create a single dynamic route that can handle different
"types" of login and logout actions:
GET /sign-up/:page
GET /login/:page
GET /logout/:page
Since the /sign-uproute behaves very much like the /login route, you are
enhancing that route too — in case that you want to use the "Sign Up"
button in your application.
Then you could take that :page parameter and use it to tell Auth0 to return
users to serverUrl/page after they log in or log out.
🛠 The steps that follow will show you how to create dynamic authentication
routes. However, if you want Express to redirect all users who log out to the
home page, you can leave your application as it is.
/**
* App Configuration
*/
app.use(express.static(...));
app.use(
auth({...})
);
You now define another local variable that all Pug templates can
access: res.locals.activeRoute. You no longer need to pass activeRoute down
to your templates from each controller.
/**
* Routes Definitions
*/
// > Home
// > Profile
/**
* Routes Definitions
*/
// > Authentication
res.oidc.login({
returnTo: page,
authorizationParams: {
screen_hint: 'signup',
},
});
});
res.oidc.login({
returnTo: page,
});
});
res.oidc.logout({
returnTo: page,
});
});
Now, you need to update your login and logout buttons to use these custom
route controllers instead of the default ones created by Express OpenID
Connect.
Why are you getting an error when logging out from the /profile page?
If you click on the "See details for this error" link from the error page, you'll
learn that the error relates to an invalid_request: The "returnTo" querystring
parameter "http://localhost:4040/profile " is not defined as a valid URL in
"Allowed Logout URLs".
During the Auth0 setup section of this guide, you defined "Allowed Logout
URLs" for the Auth0 application that represents your Express web
application in the Auth0 platform:
Allowed Logout URLs
http://localhost:4040
Auth0 can only redirect your users after they log out to the URLs listed in
that field. As such, you need to add the /profile and /external-api paths to it.
🛠 Head back to the "Applications" section from the Auth0 Dashboard. Select
your "Auth0 Express Sample" application and then click on the "Settings"
tab.
🛠 Head back to your application user interface in the browser. Visit either
the "Profile" or "External API" page. Refresh the page and try to log in and
log out. You should now stay in the same page after either action completes
without any errors.
In the next section, you'll learn how to retrieve and display user profile
information in your user interface.
How can you use req.oidc.user to create a profile page for your users?
// src/index.js
/**
* Routes Definitions
*/
// > Profile
app.get('/profile', (req, res) => {
res.render('profile', {
user: req.oidc.user,
});
});
block content
if user
div
div(class="row align-items-center profile-header")
div(class="col-md-2 mb-3")
img(
class="rounded-circle img-fluid profile-picture mb-3 mb-md-0"
src=user.picture
alt="Profile"
)
div(class="col-md text-center text-md-left")
h2 #{user.name}
p(class="lead text-muted") #{user.email}
div(class="row")
pre(class="col-12 text-light bg-dark p-4")
| #{JSON.stringify(user, null, 2)}
You obtain the user name, picture, and email from the user object that
you passed to the template from the /profile route controller.
You then display these three properties in the user interface. You only
render the content of the profile template if the user object is defined.
Finally, you display the full content of the decoded ID token within a
code box. You can now see all the other properties available for you
to use.
What is an ID token?
The profile template renders user information that you could consider
protected. Additionally, the user property is null if there is no logged-in user.
So either way, this component should only render if Auth0 has authenticated
the user.
Protecting Routes
The Express OpenID Connect library exposes a requiresAuth() middleware
function that you can use to require users to login in order to access a
specific route. Express will redirect to the Auth0 Universal Login page any
users who have not logged in and try to access the route.
/**
* Required External Modules
*/
// > Profile