A maintained and expanded fork of https://github.com/braitsch/node-login , for avoiding starting from scratch with a login UI and backend.
MIT License
(Note that the more restrictive @fortawesome/fontawesome-free share-alike terms are for the fonts themselves, not its CSS (which is under MIT); see also licenses for dev. deps..)
A maintained and expanded fork of https://github.com/braitsch/node-login.
The project name is a portmanteau of "Node" and "login" and is pronounced "noggin" (a colloquial word for "head").
So if you want Node login, use your "nogin"!
sameSite
session cookiesnode-login
While you can see CHANGES (or the 1.0.0 migration guide) to see all of the fixes and enhancements (including security fixes), over the excellent node-login package, the essential change has been to avoid the necessity of directly modifying source. This component has been retooled to allow it to be added as an npm dependency and provided command-line arguments which customize the appearance and behavior to a high degree—and using a config file or CLI flags rather than environmental variables.
You provide the app (through the --router
argument) your Express app
entry file and optionally other arguments. See the next section.
Besides these changes, there have been subsequent additions as well:
Install Node.js (minimum version of 10.4.0) and MongoDB if you haven't already. (Note that while we have provided a generic database adapter that could in theory be used to support other databases, MongoDB is the only currently supported database.)
Install the package.
npm install nogin
Install the peerDependencies
. I recommend installing install-peerdeps
(npm i -g install-peerdeps
); then install-peerdeps nogin
will
auto-install the rest.
Add a nogin.js
file (see the nogin-sample.js
file)
Add a db
directory at your project root (and probably add it to
.gitignore
and .npmignore
)
Use run-p
(which is made available by the nogin
dependency, npm-run-all
)
along with two of your own package.json
scripts, one of which to start
the mongo database, and the other to start the nogin server (note that
nodemon
is also provided as a dependency, so you could add that to
the nogin
call to watch for changes to nogin
files):
{
"scripts": {
"mongo": "mongod --port=27017 --dbpath=db --bind_ip=127.0.0.1",
"server": "nogin --localScripts --config nogin.js",
"start": "run-p -r mongo server"
}
}
(The -r
flag indicates that an error in one script will lead both to exit.)
Alternatively, you can start MongoDB in its own separate shell:
mongod
...and from within the nogin directory in another terminal, start the server:
nogin --localScripts --config nogin.js
You will most likely also want to use the --router
and possibly --fallback
, as
well as --postLoginRedirectPath /
arguments. See these options for more details.
Once the script mentions it is listening (on port 3000 by default), open a browser window and navigate to: http://127.0.0.1:3000/login
(For your live site, ensure your nogin.js
NL_SITE_URL
is pointing to this port.)
Set yourself as rootUser
in nogin.js
and add groups and privileges and
assign groups to users as relevant. Use dots as namespaces in privilege and
group names. Note that the built-in groups nogin.loggedInUsers
and
nogin.guests
will apply to all who are logged in or not, respectfully. The
privilegs should be additive from the level of guest to logged in user to
regular user to root user.
Check the privileges in your app. You can check the privileges from
req.hasPrivilege(...)
regardless of whether the user is logged in
or a guest. You can also get the privileges from /_privs
JavaScript. If you want live results, you can make a GET request to
/_privs?format=json
(or just import the helper nogin/hasPrivilege.js
).
MongoDB may end up with a process that interferes with starting a new instance.
On the Mac, you can follow these steps to resolve:
sudo lsof -i :27017
kill PID
with PID as the result of step 1 (or ifkill -2 PID
).To view as non-embedded HTML or SVG files (for copy-pasteable commands):
When no verbs are added (only flags are supplied), you can see the above for a detailed description of the available flags. We group and summarize these here (all strings unless indicated). See also "Flags available regardless of "verb"" as those also apply as server flags.
-c
/--config
- (Defaults to <cwd>/nogin.json
; may also be a JS file.)--cwd
(Defaults to process.cwd()
.)You can also look at nogin-sample.js
for how to set these values within
your own nogin.js
config file.
--secret
--NL_EMAIL_USER
--NL_EMAIL_PASS
--NL_EMAIL_HOST
--NL_EMAIL_FROM
--NL_SITE_URL
--fromText
--fromURL
--disableXSRF
(Boolean; defaults to false
.)--noHelmet
(Boolean; defaults to false
.)--noHostValidation
(Boolean; defaults to false
.)--RATE_LIMIT
(A number defaulting to 700 for a rate limit.)--transferLimit
(A string like "50mb" to be passed to express.json()
express.urlencoded()
)--csurfOptions
(A string, or, in config, an object; defaults to{cookie: {signed: true, sameSite: "lax"}
; note that if you are on{cookie: {secure: true, signed: true, sameSite: "lax"}
).--helmetOptions
(A string, or, in config, an object; defaults to{frameguard: {action: "SAMEORIGIN"}}
). Note that SAMEORIGIN
is requiredaction
to allow nogin
to be used within your site's iframes.--sessionOptions
(A string, or, in config, an object; defaults to{resave: true, saveUninitialized: true}
along withcookie: sessionCookieOptions
, secret
, andstore: MongoStore.create({mongoUrl: DB_URL})
--sessionCookieOptions
(A string, or, in config, an object; defaults to{sameSite: 'lax'}
)--NS_EMAIL_TIMEOUT
(number of milliseconds, defaulting to 5000)--PORT
(number, defaulting to 3000)-a
/--adapter
(Defaults to "mongodb", the only current option.)--rootUser
- Users who are granted all available privileges to view and--requireName
(Default is false
.)--countryCodes
(Two-letter country codes as JSON array; defaults to/app/server/modules/country-codes.json
.)--localesBasePath
(Defaults to app/server
; use if need to redefineThese should normally not changing, but can be changed to tweak the HTML that is rendered in emails or on the server.
--composeResetPasswordEmailView
(Defaults to /app/server/views/composeResetPasswordEmail.js
)--composeActivationEmailView
(Defaults to /app/server/views/composeActivationEmail.js
)--injectHTML
(No extra HTML is injected by default)--favicon
(String path; defaults to blank.)--stylesheet
(String path; defaults to no extra stylesheets being used.)--noBuiltinStylesheets
(Boolean, defaults to false
)--localScripts
(Boolean, defaults to false
)--userJS
(None by default)--userJSModule
(None by default)These should primarily only be used with testing:
--useESM
(Boolean, defaults to false
.)--noPolyfill
(Boolean, defaults to false
.)This is for changing the names or behavior of existing routes. See "Adding routes" for supporting additional routes.
--postLoginRedirectPath
(Path/URL to which to redirect after login; defaults/home
) (or locale equivalent), but you should probably set it/
).--customRoute
(Multiple strings in format <locale>=<route>=<path>
)--crossDomainJSRedirects
(Boolean, defaults to false
.)-s
/--SERVE_COVERAGE
(Boolean; defaults to false
.)--staticDir
(One or more string paths)--middleware
(One or more middleware to be required)--fallback
- If you need a default static file server and not justimport express from 'express';
/**
* @param {import('express').Request} req
* @param {import('express').Response} res
* @param {import('express').NextFunction} next
* @returns {void}
*/
export default function fallback (req, res, next) {
express.static('.', {
setHeaders (resp /* , path, stat */) {
resp.set({
'Content-Security-Policy': `object-src 'none';`
});
}
})(req, res, next);
}
--router
- This is where your own (Express) app should be. Note: The following/login
, /logout
, /home
, /signup
, /accessAPI
, /reset-password
, /lost-password
, /delete
, /reset
/login
, /logout
, /home
, /signup
, /accessAPI
, /reset-password
, /activation
, /users
, /coverage
, /groups
, /privileges
, _lang
, _privs
/**
* @param {import('express').Application} app
* @param {{userJS: string}} opts
* @returns {void}
*/
export default function router (app, opts) {
// Grab your `nogin.js` options here as needed
console.log('Started with options:', {
...opts,
secret: '<HIDDEN>',
NL_EMAIL_PASS: '<HIDDEN>'
});
app.get('/', (req, _res, next) => {
// To see your user session info (and determine privileges), you can get
// them from `req.sesssion?.user`:
console.log('req.session', {
...req.session?.user,
_id: '<some unique ID>',
name: 'Brett Zamir',
email: '<the user email address>',
user: 'brettz9',
pass: '<the password hash>',
country: 'US',
activationCode: '<activation code hash>',
activated: true,
passVer: 1,
date: 1725865509592,
cookie: '<cookie hash>',
ip: '::ffff:127.0.0.1'
});
// We just use express' approach to point `/` to the path `/index.html`.
req.url = '/index.html';
// Or instead add optional config to conditionally point to any
// Cypress-instrumented entry file:
// req.url = instrumented
// ? '/instrumented/index.html'
// : '/index.html';
// Or point the user to the login page if they are not yet logged in
// req.url = req.session?.user
// ? '/index.html'
// : '/login';
next();
});
}
nogin
-d
/--JS_DIR
- (Defaults to /app/public
; used for pointing toOne can also add a verb to nogin
(e.g., nogin read
) which performs a
different behavior from creating a server.
help
- Use with one of the verbs below to get help for that commandread
/view
- View user account(s)update
- Update user account(s)add
/create
- Create new user account(s)remove
/delete
- Remove user account(s)listIndexes
- List indexes of the nogin databasehelp
)Defaults in parentheses:
--loggerLocale
("en-US")--noLogging
(false
)-n
/--DB_NAME
("nogin")-t
/--DB_HOST
("127.0.0.1")-p
/--DB_PORT
(27017)-u
/--DB_USER
-x
/--DB_PASS
These are are all multiple
(one to be added for each user being viewed/added/etc.).
Unless notes, all types are strings.
--user
(as the default option, the flag --user
can be omitted)--name
--email
--country
(Two digit recognized country code)--pass
--passVer
(A number indicating the current schema version; should always be--date
(A number timestamp for record creation date)--activated
(A boolean)These are shared but will primarily only be of interest in internal nogin testing:
--activationCode
--unactivatedEmail
--activationRequestDate
(A number timestamp)add
/create
Note that the CLI API for the add
and update
verbs does not currently
perform all validation that the UI does, so you will need to have some
familiarity with nogin internals to be sure to include all required fields.
--userFile
- Path to JSON file containing data to populate--cwd
- Used with userFile
remove
/delete
--all
- Boolean to indicate desire to remove all user records!pnpm i
(local install to get devDeps)pnpm build-docs
docs/jsdoc/index.html
Questions and suggestions for improvement are welcome.
For developing docs, see DEVELOPING.
csurf
and usage@fortawesome/fontawesome-free
dependency (and ifapp/server/views/account.js
) to be passed toapp/server/routeList.js
) and saved in the database alonghome
(also built by account.js
) (unless hidden?);json-editor
?
passport-next
integration
CryptoKey
CryptoKeyPair
).name
at aview-users
as well as more encompassingview
privilege)reset
from GET page to POST on the user (admin) page.PaymentRequest
so privilege groups can be tied to<link rel=next/prev>
./accessAPI
(GET) to explain API and also possibly consolidate/user/<username>
(GET) script for admins and others/group/<groupname>
(GET) script for admins and otherslocalScripts
which uses CDN but generates fallbackuniqueEmails
mode). Alternatively, couldrequired
fields, etc.)jsdom
to dominum
(once latter may be capable), as latterjamilih
for the integrationuniqueEmails: true
) is enabled as users concerned withuniqueEmails
, require username be