Auth
Passport-based module to authorize user-requests, for example with google.
Features
- Provides a simple to use middleware, that handles all the sessioning and authorizing
- Automatically refreshes the access-token if it expired, before calling the next middleware
- Provides the necessary routes to completely handle the login-process
- Provides event-based-auth-hooks so you can dely/reject authorization
Configuration
- Copy the demo-config from
doc/auth.json
to config/ENVIRONMENT/auth/auth.json
in your project
- Replace all the upper-case strings with your corresponding config
- Replace other configurations if necessary (in the demo-config,
http://localhost:8000
is the backend, and http://localhost:9000
is the frontend)
- Delete all the strategies that you don't need from the config
Setup
- In your http-extension-module in your application run
npm install @5minds/auth --save
- In your http-extensions
ioc_module.js
- Require the module with
const auth = require('@5minds/auth/ioc_module');
- Register the module at the IoC-Container with:
auth.registerInContainer(container);
- add
'auth'
as dependency to your http-extension
- In your http-extensions
initializeMiddlewareBeforeRouters
call
this.auth.initializeSessioning(this.app);
Usage
-
Let the IoC-Container inject the auth-module into the classes, that register the routes that need authorization
-
add the auth-modules middleware to the routes that need authorization, like so:
this.router.get('/tasks/:smartlistId', this.auth.middleware, YOUR_NEXT_MIDDLEWARE_GOES_HERE);
-
If the authorization failed for some reason, the middleware will redirect to the failRedirect
-route provided in the config, and no other middleware will be called
-
If the authorization succeeded, the request now has a session-object and a user-object. The user-object has the following structure:
for google-auth
req.user = {
credentials: {
access_token: 'SOME_OAUTH_ACCESS_TOKEN',
refresh_token: 'SOME_OAUTH_REFRESH_TOKEN',
refresh_after: 'THE_ACCESS_TOKEN_EXPIRATION_TIME',
},
profile: {
name: {
first: 'Heiko',
last: 'Mathes',
display: 'Heiko Mathes',
},
language: 'de',
image: 'https://someUrl',
email: 'heiko.mathes@5minds.de',
},
userToken: 'SOME_TOKEN_THAT_IDENTIFIES_THE_USER',
strategy: 'google',
}
for local password-auth:
req.user = {
profile: THE_USER_PROFILE_OBJECT_FROM_YOUR_APP,
strategy: 'password',
}
local password-strategy
For the local password-strategy to work, you need to listen to the auth-modules userLogin
-event at some point in your application.
This event will get fired, everytime a user wants to login. A Demo-implementation could look like this:
this.auth.on('userLogin', (userParams) => {
this.user.getUserByMailAddress(userParams.username)
.then((userInfo) => {
if (!userInfo.password === this.hash(userParams.password)) {
logger.debug(`${userParams.username} tried to login with a wrong password`);
return Promise.reject(new Error('password mismatch'));
}
return userParams.resolve(userInfo);
})
.catch((error) => {
userParams.reject(error);
});
});
The userParams
-Object looks like this:
{
username: 'SOMEUSERNAME',
password: 'SOMEPASSWORD',
resolve: FUNCTION,
reject: FUNCTION,
}
You need to call resolve, when the user could be verified, or reject if something went wrong.
Whatever you give it as parameter in the userParams.reject-method will be in req.user.profile in later requests
Events
For all auth-medthods, the following events can be listened on:
requestAuthorized
This event gets called, every time a request is about to get authorized. Every listener gets a userParams-Object that looks like this:
{
request: SOMEREQUEST,
user: USER\_OBJECT,
resolve: FUNCTION,
reject: FUNCTION,
}
- Only when all listeners have called the resolve-function will the request
be allowed to the next middleware (the one after the auth.middleware)
- When any one of the listeners rejects, the whole request will be rejected
with a 403 - Forbidden
- Every listener must call resolve or reject (but not both) exactly once!