Library / SDK
bradtraversy/storybooks avatar
bradtraversy/storybooks

StoryBooks is a small Express and MongoDB app with Google sign-in

Node.js app with Google OAuth

591 stars922 forksJavaScriptMIT

At a glance

What is it?
StoryBooks is a Node.js application for writing public and private stories, built on Express, Handlebars, MongoDB and Passport's Google OAuth strategy. It is a teaching-sized codebase, useful as a reference for session handling and OAuth in Express, and it is not a platform to build a product on.
Who is it for?
Adopt StoryBooks if you are learning how a Google OAuth login, an Express session and a MongoDB model fit together in one readable codebase, since the whole application is a handful of directories and a manifest you can hold in your head. Do not adopt it as the basis of a product, because the dependency set is dated, the session store and configuration are minimal, and the project publishes no releases.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 75 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A story app shaped like an Express tutorial

StoryBooks is a Node.js application for creating public and private stories from your life, and the description in the repository is blunt about the technology: Node.js, Express, MongoDB and Google OAuth for authentication. The scope is deliberately small, and reading the directory listing shows how small. At the top level there is app.js as the entry point, then config/, helpers/, middleware/, models/, routes/, public/ and views/, plus a scripts/ directory holding the post-install script, an .env.example, a .gitignore and the licence file. That is the canonical Express application layout, one directory per concern, and it is the reason the project is worth an engineer's attention. Nothing here is novel. What the codebase provides is a working end to end example of session-backed authentication with a third party identity provider, content stored in a document database, and server rendered views. For a developer who has written controllers and models before but never wired an OAuth callback to a session, that is a small, complete, readable thing to take apart.

The two script entry points and the environment switch

The package manifest has three scripts, and the two run modes differ by a single environment variable, which is a detail worth noticing because it shows the intended deployment shape. The start script runs cross-env NODE_ENV=production node app, and the dev script runs cross-env NODE_ENV=development nodemon app. The use of cross-env rather than setting the variable inline in the shell is what makes the same command work on Windows, which is a small portability decision that many projects of this size skip. Nodemon handles the reload in development, so the two commands differ in tooling as well as in environment. The third script is postinstall, which runs node ./scripts/post-install.js, and that is the thread to follow next, because it is where the environment file comes from. The package manifest names the entry point as app.js, and the versions are pinned in the usual caret style: express 4.22.1, mongoose 7.8.9, express-session 1.19.0, passport 0.4.1 and passport-google-oauth20 2.0.0, with dotenv 8.6.0, connect-mongo 4.6.0, express-handlebars 4.0.6, method-override 3.0.0, moment 2.30.1, morgan 1.10.1 and fs-extra 9.1.0 alongside them.

The postinstall script that creates your .env

The setup sequence has a convenience feature that is worth understanding rather than fighting. During install, the postinstall script attempts to create .env automatically from .env.example, and if .env was not created you copy .env.example to .env manually. That means the flow has a fallback for every environment, including one where the script cannot write the file, and it also means the developer never has to invent the variable names. The example file itself is four lines long.

env
PORT=3000
MONGO_URI=xxxxx
GOOGLE_CLIENT_ID=xxxxx
GOOGLE_CLIENT_SECRET=xxxxx

The real .env then carries the four values. The port is 3000, the MongoDB connection string, and the two Google credentials. The MONGO_URI value the documentation shows is a full Atlas connection string of the form mongodb+srv://<username>:<password>@<cluster-url>/<database>?retryWrites=true&w=majority, and the worked example is mongodb+srv://appuser:[email protected]/storybooks?retryWrites=true&w=majority. The database name in that example is the application name itself, which is a reasonable convention. The presence of a .gitignore in the tree alongside .env.example is the important safety detail, because the file that holds the client secret must never be committed.

Google OAuth, step by step

The authentication setup is a five step checklist in the documentation, and it is worth following exactly rather than improvising, because the redirect URI is the part people get wrong. In Google Cloud Console you create or select a project, then configure the OAuth consent screen, then create OAuth 2.0 Client ID credentials for a Web application. The fourth step is adding an authorized redirect URI, and the documented value is a local address on port 3000.

text
http://localhost:3000/auth/google/callback

The fifth step copies the generated Client ID and Client Secret into .env as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET. The path in that callback URL is not arbitrary. It is the route your Express app has to expose for Passport's Google strategy to hand the authorization code back to, and the port comes from the PORT value in .env. Change the port without changing the registered redirect URI and Google will refuse the callback, which presents as a login that returns to an error page rather than a clear configuration message. On the server side the pieces are the standard ones. Passport 0.4.1 with the passport-google-oauth20 strategy 2.0.0 handles the flow, express-session 1.19.0 provides the session, and connect-mongo 4.6.0 is what lets the session live in MongoDB rather than in process memory, which is what makes the app work across more than one instance or a restart.

Server rendered views and the public and private split

The views/ and public/ directories tell you the rendering model. The app is server rendered, with express-handlebars 4.0.6 as the template engine, so a request produces HTML through a template rather than a JSON payload consumed by a client framework. public/ holds the static assets served alongside it. The core domain concept is a story with a visibility, and the distinction between public and private is the interesting part of the design rather than a detail. A story that is public is readable by anyone, and one that is private is readable by its author, which means the authorisation check happens on read rather than on write. The models/ directory holds the Mongoose schemas for that, with mongoose 7.8.9 doing the mapping, and middleware/ holds the functions that decide whether the current session's user may see a given document. The helper directory is separate again, which is where you would expect shared utilities to live, and method-override 3.0.0 is in the dependency list, which is how a form post can act as a PUT or DELETE, a pattern from the era when HTML forms only spoke GET and POST.

Running it, and the limits of the dependency set

Two commands cover the whole runtime story.

bash
# Run in development
npm run dev

# Run in production
npm start

That is the entire operational surface, and it is also where the constraints live. The project publishes no GitHub releases, and the last push to the repository was on 2026-08-09, so there is no version history to consult and no upgrade path to plan. The dependency set is the more substantive limit. dotenv is pinned at 8.6.0 and moment at 2.30.1, and moment is the momentjs package, and it is a large dependency for what it does. express is on the 4.x line rather than 5. There is no test script in the manifest at all, and the only devDependencies are cross-env and nodemon, so there is no suite to run before a change and no linting configured. None of that matters for reading the code, and all of it matters if you are about to build something on top. The realistic uses are learning the OAuth and session flow, using the app as a starting point for a small internal tool, or lifting the authentication and model structure into a codebase that has its own dependency policy.

Editorial conclusion

Adopt StoryBooks if you are learning how a Google OAuth login, an Express session and a MongoDB model fit together in one readable codebase, since the whole application is a handful of directories and a manifest you can hold in your head. Do not adopt it as the basis of a product, because the dependency set is dated, the session store and configuration are minimal, and the project publishes no releases. Verify two things before you build on it: that the OAuth redirect URI you register in Google Cloud Console matches the port your app actually binds, since the documented callback is http://localhost:3000/auth/google/callback and a different port means the callback fails silently at the browser, and that your MongoDB deployment suits the connection string shape, since the example is an Atlas cluster URI with retryWrites and majority write concern. The practical first step is npm install, which also triggers the postinstall script that copies .env.example to .env, then fill in the four values and run npm run dev.

Frequently asked questions

What is StoryBooks?

It is a Node.js app for creating public and private stories from your life, using Express, MongoDB and Google OAuth for authentication. The repository describes it as a Node.js/Express/MongoDB app with Google OAuth.

How do I set up StoryBooks locally?

Run npm install, which triggers the postinstall script that copies .env.example to .env automatically, then fill in PORT, MONGO_URI, GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, and start it with npm run dev. If .env was not created during install, copy .env.example to .env manually.

What redirect URI do I register for StoryBooks Google OAuth?

The documented authorized redirect URI is http://localhost:3000/auth/google/callback, and it must match the port your app binds. You create OAuth 2.0 Client ID credentials for a Web application in Google Cloud Console and copy the Client ID and Client Secret into .env.

Where does StoryBooks store its data and sessions?

Data goes into MongoDB through Mongoose 7.8.9, using a connection string in MONGO_URI such as mongodb+srv://appuser:[email protected]/storybooks?retryWrites=true&w=majority. Sessions use express-session with connect-mongo 4.6.0, so session state is kept in MongoDB.

How do I run StoryBooks in production mode?

Run npm start, which sets NODE_ENV=production through cross-env and starts app.js with node. The development command is npm run dev, which sets NODE_ENV=development and runs the same entry point under nodemon.

Official sources

  1. bradtraversy/storybooks on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bradtraversy-storybooks.svg)](https://hysenlabs.com/projects/bradtraversy-storybooks)

Was this useful?