Custom authentication system with NextAuth.js.
Good to know
-
When signing in with a social provider without having an account, you automatically get an account.
-
When signing in with GitHub (fails because no public email address), code has no way to know where to return (/auth/signin or /auth/register). See: [...nextauth.js]
- Features
- Technologies
- Installation
- Routes
- Auth Providers
- SSL on localhost
- JWT
- SVG
- Deployment Checklist
- Notes
- Sign in and register with OAuth and credentials
- Protected API routes
- Persisting users in database
- Sending out welcome email
- Show/hide password toggle
- Forgot password flow
Technology | Purpose |
---|---|
Next.js | SSR and SSG framework for React |
NextAuth | Authentication solution |
Mongoose | ODM for MongoDB |
bcrypt | Password encryption |
validator | Email address validation |
sass | Custom utility classes |
SendGrid | Email service |
styled-components | Theming and component-scoped styling |
- Clone repo:
git clone https://github.com/ronnevinkx/next-auth.git
- Install package:
npm i
- Setup
.env
file as indicated in.env.example
- List desired OAuth providers in
[...nextauth].js
- Run locally:
npm run dev
Route | Description |
---|---|
/auth/signin |
Sign in |
/auth/register |
Register |
/auth/forgotPassword |
Forgot password - email form |
/auth/resetPassword |
Reset password - new password form |
/api/users |
Users API - protected |
/api/auth/* |
NextAuth handler |
/api/account/forgotPassword |
Send email with token link |
/api/account/resetPassword |
Change password |
- GitHub
- Credentials
-
After creating the app in the developer console, make sure to click Create Test App and use those credentials on localhost.
-
Set Advanced Access for public_profile (App Review > Permissions and Features).
-
Do the Data Use Checkup
-
Facebook Login should now work!
For a live app, First get Advanced Access for public_profile
through the console (section App Review, action Get Advanced Access).
Make sure Facebook returns email address if you want to persist user (because you can also create FB account with phone number).
- Create certificate:
openssl req -x509 -out localhost.crt -keyout localhost.key \
-days 365 \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
-
Move to
certificates
folder in project root, add this folder to.gitignore
-
Click on certificate to add to keychain, look it up and set to
Always Trust
-
Create custom
server.js
:
const { createServer } = require('https');
const { parse } = require('url');
const next = require('next');
const fs = require('fs');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const httpsOptions = {
key: fs.readFileSync('./certificates/localhost.key'),
cert: fs.readFileSync('./certificates/localhost.crt')
};
app.prepare().then(() => {
createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(3000, err => {
if (err) throw err;
console.log('> Server started on https://localhost:3000');
});
});
- Change package.json file:
"scripts": {
"start": "node server.js"
},
- Comment out
pages
prop in[...nextauth].js
Now run npm run start
- Installed node-jose-tools globally (
npm install -g node-jose-tools
) - Created
JWT_SIGNING_PRIVATE_KEY
withjose newkey -s 256 -t oct -a HS512
I've chosen SendGrid as email service and have set up the environment variable SENDGRID_API_KEY
for that, but you can choose anything you like. See /utils/mailer.js
.
- styled-components rendered on server
- Welcome and Forgot Password mails sent out and received
- Facebook sign in and register
- Google sign in and register
- Twitter sign in and register
- GitHub sign in and register
- Credentials sign in and register
- Configured
.babelrc
to use styled-components with Next.js - styled-components are serverside rendered through custom
_document.js