UNPKG

@ssense/auth

Version:

The Auth Module is a combination for an HTTP middleware (compatible with express and restify) and a Typescript decorator. Used together, they allow protection for all the routes of your application, handling user authentication and authorizations.

153 lines (117 loc) 6.4 kB
## Auth Module The Auth Module is a combination of an HTTP middleware (compatible with express and restify) and a Typescript decorator. Used together, they allow to protect all the routes of your application, handling user authentication and authorizations. ### Disclaimer You can find the full list of changes in the `CHANGELOG.md` but the TLDR is that +2.0.0 of this lib requires `node>=14.18`. ### How to use #### Add the AuthModule middleware You first have to load the AuthModule middleware to protect all your application's routes. Example usage: ```typescript // This example covers restify, but you can also use the middleware if you use express import { Server } from 'restify'; import { AuthModule } from '@ssense/auth'; // Create restify server const server = restify.createServer(/* Set your server options here */); // Create AuthModule (the configuration object is fully optional, refer to the typescript definition file for more detail) const authModule = new AuthModule({ // Override the default SSENSE authorization server (only use for development purpose) authServerHost: 'test.ssense.com', // Use HTTP protocol instead of HTTPS for the authentication server (don't use in production!) authServerSecure: false, // All the routes will be protected by default, add the routes that you want to keep public here publicRoutes: [ /^\/+$/, // Set home page as public /^(\/robots\.txt|\/favicon\.ico)$/, // Only for example purpose: allow anonymous requests to /robots.txt and /favicon.ico ], publicHttpMethods: [ 'DELETE', // Just an example, in this case all HTTP DELETE requests will be allowed, regardless of the route ], // Specific callback to handle unauthorized requests, a generic error page will be displayed if not present (res.statusCode set to 403 by default) onForbidden: (req, res, next) => { res.send('You are not allowed to access this page'); next(); }, }); // Add middleware to our server server.use(authModule.authenticate()); ``` Just by adding this middleware, all your application's routes will be protected from anonymous requests (a valid ssense.com email address is required). The user's authentication is also fully managed, you can focus on your business case without having to take care about authentication. #### Retrieving user's information at the controller level After loading the AuthModule middleware, all the controllers of your application will have an extra `auth` param in the `request` object. This param is an instanceof of `AuthInfo`, giving the currently logged in user's information, as follows: ```typescript interface AuthInfo { // Id of the currently logged in user, for an SSENSE employee, will be the corresponding email address id: string; // Type of the currently logged in account (possible values are "user" and "service") type: string; // List of scopes available for the currently logged in user scopes: string[]; // Raw JWT token used for authenticating the currently logged in user token: string; // Shortcut method indicating if the currently logged in account has a given scope hasScope(scope: string): boolean; // Shortcut method indicating if the currently logged in account has all the given scopes hasScopes(scopes: string[]): boolean; } ``` Let's take an example: ```typescript // Assuming that the AuthModule middleware has already been loaded // Example controller function public async myControllerFunction(req, res, next): Promise<any> { // req has now an extra "auth" property res.send('You are currently logged in as ' + req.auth.id + ', you are logged in as a ' + req.auth.type + ' account'); res.end(); } ``` #### Automatically protect controller functions based on current user's scopes You can automatically protect your controller's function by allowing access only to users that have the appropriate scopes. To enable this feature, you can use the `requireScope()` typescript decorator, as in the example below: ```typescript // Assuming that the AuthModule middleware has already been loaded import { AuthModule } from '@ssense/auth'; // Enable the auto protection feature based on user's scopes @AuthModule.requireScope('scope1') public async myControllerFunction(req, res, next): Promise<any> { // req has now an extra "auth" property res.send('You are currently logged in as ' + req.auth.id + ' and you have at least one required scope to access this function'); res.end(); } ``` Using the `@AuthModule.requireScope('scope1')` line, logged in users need to have the specififed scope to access your function. You can also allow access to a function for several scopes, using `@AuthModule.requireScope(['scope1', 'scope2'])`, in this case the authenticated user needs to have **at least one of** the scopes passed in parameter to be able to access this function. If they don't have any of the possible scopes, they will get a 403 error page, the response will automatically be sent and your function will not even be called. If you want to check for several scopes, you can use the `@AuthModule.requireAllScopes()` decorator, which takes a string[] as parameter. In this case the authenticated user needs to have **all of** the scopes passed in parameter to be able to access this function. Alternatively, you can use the same functionality as a middleware: ```typescript import { AuthModule } from '@ssense/auth'; @Get('/something', AuthModule.scopeMiddleware(['resources:operation'])) public async myControllerFunction(req, res, next): Promise<any> { //... } ``` The `scopeMiddleware` function have an optional 2nd parameter where `true` is "all of the scopes" and `false` is "at least one of the scopes". default to true This has the advantage to be usable on the controller level: ```typescript import { AuthModule } from '@ssense/auth'; @injectable() @Controller('/somethings', AuthModule.scopeMiddleware(['resources:operation']) export class SomeController extends BaseController { //... } ``` And can be chainable : ```typescript import { AuthModule } from '@ssense/auth'; @Get('/something') public async getSomething(req: Request, res: Response, next: Next): Promise<void> { if(req.query.something){ AuthModule.scopeMiddleware(['resources:operation'])(req,res,next) } next() } ```