From bf5716c674efc4b41eaa57103810bd71845828c4 Mon Sep 17 00:00:00 2001 From: Nico Domino Date: Tue, 11 Aug 2020 14:33:44 +0200 Subject: [PATCH] Add: ldap auth tutorial example (#566) * add: ldap auth tutorial example * update: tutorials page list * update: NEXTAUTH_SECRET * Update tutorials.md Co-authored-by: Iain Collins --- www/docs/tutorials.md | 6 ++- www/docs/tutorials/ldap-auth.md | 84 +++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 www/docs/tutorials/ldap-auth.md diff --git a/www/docs/tutorials.md b/www/docs/tutorials.md index e627d953f6..7d0ffb3d9d 100644 --- a/www/docs/tutorials.md +++ b/www/docs/tutorials.md @@ -19,5 +19,9 @@ title: Tutorials and Explainers * [Testing with Cypress](tutorials/testing-with-cypress) +### How to use the Credentials Provider - \ No newline at end of file +* [LDAP Authentication](tutorials/ldap-auth-example) + + + diff --git a/www/docs/tutorials/ldap-auth.md b/www/docs/tutorials/ldap-auth.md new file mode 100644 index 0000000000..a5c19b9a49 --- /dev/null +++ b/www/docs/tutorials/ldap-auth.md @@ -0,0 +1,84 @@ +--- +id: ldap-auth-example +title: LDAP Authentication +--- + +NextAuth.js provides the ability to setup a [custom Credential provider](/configuration/providers#sign-in-with-credentials) which we can take advantage of to authenticate users against an existing LDAP server. + +You will need an additional dependency, `ldapjs`, which you can install by running `npm install ldapjs`. + +Then you must setup the `Providers.Credentials()` provider key like so: + +```js title="[...nextauth].js" +const ldap = require("ldapjs"); +import NextAuth from "next-auth"; +import Providers from "next-auth/providers"; + +const options = { + providers: [ + Providers.Credentials({ + name: "LDAP", + credentials: { + username: { label: "DN", type: "text", placeholder: "" }, + password: { label: "Password", type: "password" }, + }, + authorize: async (credentials) => { + // You might want to pull this call out so we're not making a new LDAP client on every login attemp + const client = ldap.createClient({ + url: process.env.LDAP_URI, + }); + + // Essentially promisify the LDAPJS client.bind function + return new Promise((resolve, reject) => { + client.bind(credentials.username, credentials.password, (error) => { + if (error) { + console.error("Failed"); + reject(); + } else { + console.log("Logged in"); + resolve({ + username: credentials.username, + password: credentials.password, + }); + } + }); + }); + }, + }), + ], + callbacks: { + jwt: async (token, user, account, profile, isNewUser) => { + const isSignIn = user ? true : false; + if (isSignIn) { + token.username = user.username; + token.password = user.password; + } + return token; + }, + session: async (session, user) => { + return { ...session, user: { username: user.username } }; + }, + }, + secret: process.env.NEXTAUTH_SECRET, + jwt: { + secret: process.env.NEXTAUTH_SECRET, + encryption: true, // Very important to encrypt the JWT, otherwise you're leaking username+password into the browser + }, +}; + +export default (req, res) => NextAuth(req, res, options); +``` + +The idea is that once one is authenticated with the LDAP server, one can pass through both the username/DN and password to the JWT stored in the browser. + +This is then passed back to any API routes and retrieved as such: + +```js title="/pages/api/doLDAPWork.js" +token = await jwt.getToken({ + req, + secret: process.env.NEXTAUTH_SECRET, +}); +const {username, password} = token; +``` + +> Thanks to [Winwardo](https://github.com/Winwardo) for the code example