This project uses Feathers. An open source web framework for building modern real-time applications. It's a modification of Nick Baroni's example on the subject that you can find here. It was revised to work with the current 4.x.x version
Followed the logic explained in the previous article with the following modifications
-
Modified the mailer service to work with gmail api with oauth2 authentication to avoid the trouble of having to Enable Less Secure Apps as explained by Nick Roach in his medium article here.
-
Used short codes (resetPwdShort) instead of the magic link (from resetPwdLong) that was used in the mother article
-
Removed the account authentication logic that used to happens after the resetPWdShort action for authmanagement explained here and and the hook that disallowed local authentication for external providers there by making it a candidate for Anonymous authentication.
-
I then went to config/default.js and created a new custom strategy called "passwordless":
"authentication":{ ... "authStrategies": [ "jwt", "passwordless" ], "passwordless": { "usernameField": "email", "passwordField": "email" } ... }
-
Then defined it as shown below:
const {AuthenticationBaseStrategy, AuthenticationService, JWTStrategy } = require('@feathersjs/authentication'); const { NotAuthenticated} = require('@feathersjs/errors'); ... class PasswordlessStrategy extends AuthenticationBaseStrategy { async authenticate(authentication, ) { if(!authentication.token) { let email; // check if user with email (& or phone) exists const {total,data} = await this.app.service('users').find({ query:{ email:authentication.email } }); if(total>0) email=data[0].email; // if not create one if(!email){ let newUser = await this.app.service('users').create({email:authentication.email}); // verify this jama: email=newUser.email; } // console.log('now use this to play the gem ',email); // use their email (& or phone) address from database to generate a password reset code const res = await this.app.service('authManagement').create({ action:'sendResetPwd', value:{email} }); // console.log('token sent ',res); // send it to them via their email (& or phone) address return { accessToken:null, message: `token sent to ${res.email}` }; } //when they return the code check if their email and code const {email,token}=authentication; // console.log(authentication); // match by running a resetPwdShort if they do, authenticate // if it expired say so and prompt them to retry // if invalid do the same try{ const res= await this.app.service('authManagement').create({ action:'resetPwdShort', value:{ user:{email}, token } }); console.log(res); return { email, }; }catch(err){ console.log('which error: ',err.message); throw new NotAuthenticated('Your ticket has expired. Request for a new one'); } } }
-
Yes ofcourse I used feathers-sequelize for postgres but this could do for any other datasource.
- Download the example or clone the repo:
git clone https://github.com/jermsam/feathers-passwordles-authentication.git your-app
- Change into your app's directory and download the dependencies
cd your-app
yarn
- create a .env file
touch .env
- create your postgres database and inside the .env file define the postgres database connection variables
host=YOURDATABASEHOST
port=YOURDATABASEPORT
username=YOURDATABASEUSERNAME
pwd=YOUR PWD
db=YOURDATABASENAME
yarn dev
For more information on all the things you can do with Feathers visit docs.feathersjs.com.