Core components
Server core
Authentication & authorization
25 min
overview the authentication & authorization component is a critical element of the ir engine's server core that manages user identity verification and access control it ensures that only legitimate users can access the system and that they can only perform actions they are permitted to do by implementing a comprehensive security layer using json web tokens (jwt) and scope based permissions, this component protects sensitive data and functionality from unauthorized access this chapter explores the implementation, workflow, and security mechanisms of authentication and authorization within the ir engine core concepts authentication authentication verifies the identity of users identity verification confirms that users are who they claim to be credential validation checks usernames, passwords, or third party tokens session management maintains user identity across multiple requests token issuance provides secure tokens for subsequent requests multiple strategies supports various authentication methods this process ensures that only legitimate users can access the system authorization authorization controls what authenticated users can do permission checking determines if users can perform specific actions scope based access assigns granular permissions to users resource protection restricts access to sensitive data role management groups permissions into roles for easier assignment context aware rules applies permissions based on the current context this process ensures that users can only access resources they are permitted to use json web tokens jwt serves as the primary authentication mechanism stateless tokens contains all necessary information without server storage digital signatures ensures token integrity and authenticity expiration limits token validity to enhance security payload customization stores user specific information cross service compatibility works across different parts of the system this token based approach provides secure and efficient authentication implementation authentication configuration authentication settings are defined in the application configuration // simplified from src/appconfig ts export const authentication = { // secret key for signing jwts secret process env auth secret || 'default secret change me', // entity and service for user identity entity 'identity provider', service 'identity provider', // available authentication strategies authstrategies \['jwt', 'local'], // jwt configuration jwtoptions { header { type 'access' }, audience 'https //ir engine com', issuer 'ir engine', algorithm 'hs256', expiresin '1d' }, // local authentication configuration local { usernamefield 'email', passwordfield 'password' }, // oauth provider configuration oauth { google { key process env google client id, secret process env google client secret, scope \['email', 'profile'], nonce true }, github { key process env github client id, secret process env github client secret } // other providers }, // paths that don't require authentication whitelist \[ '/authentication', '/users/create', '/health' ] }; this configuration defines the secret key for signing jwts specifies available authentication strategies configures jwt options like expiration and algorithm sets up oauth providers for social login lists paths that don't require authentication authentication service setup the authentication service is configured in a dedicated module // simplified from src/user/authentication ts import { authenticationservice, jwtstrategy } from '@feathersjs/authentication'; import { localstrategy } from '@feathersjs/authentication local'; import { oauth, oauthstrategy } from '@feathersjs/authentication oauth'; import { application } from ' /declarations'; / configures authentication for the application @param app feathers application / export default function(app application) void { const authentication = new authenticationservice(app); // register jwt strategy authentication register('jwt', new jwtstrategy()); // register local strategy (username/password) authentication register('local', new localstrategy()); // register oauth strategies authentication register('google', new oauthstrategy()); authentication register('github', new oauthstrategy()); // add authentication service app use('/authentication', authentication); // configure oauth app configure(oauth()); } this function creates an authentication service registers various authentication strategies adds the authentication service to the application configures oauth for social login authentication hook the authentication hook verifies user identity // simplified from src/hooks/authenticate ts import { authenticate as feathersauthenticate } from '@feathersjs/authentication/hooks'; import { hookcontext } from '@feathersjs/feathers'; import { notauthenticated } from '@feathersjs/errors'; import config from ' /appconfig'; / authentication hook @param context hook context @returns modified context / export const authenticate = async (context hookcontext) => { // skip for internal calls that already have a user if (!context params provider && context params user) { return context; } // check if the path is whitelisted const path = context path; if (config authentication whitelist includes(path)) { return context; } try { // authenticate using jwt strategy await feathersauthenticate('jwt')(context); // get the user id from the jwt payload const userid = context params user? id; if (!userid) { throw new notauthenticated('user id not found in token'); } // get the full user object const user = await context app service('users') get(userid); // update the user in the context context params user = user; return context; } catch (error) { // try api key authentication if jwt fails const apikey = context params headers? \['x api key']; if (apikey) { const apikeyrecord = await context app service('api keys') find({ query { key apikey, active true } }); if (apikeyrecord total > 0) { const userid = apikeyrecord data\[0] userid; const user = await context app service('users') get(userid); context params user = user; return context; } } // if all authentication methods fail throw new notauthenticated('authentication failed'); } }; this hook checks if the request is internal or the path is whitelisted attempts to authenticate using the jwt strategy retrieves the full user object if jwt authentication succeeds falls back to api key authentication if jwt fails throws an error if all authentication methods fail scope verification hook the scope verification hook checks user permissions // simplified from src/hooks/verify scope ts import { hookcontext } from '@feathersjs/feathers'; import { forbidden, notauthenticated } from '@feathersjs/errors'; / verifies that the user has the required scope @param resourcetype type of resource (e g , 'project', 'user') @param permission required permission (e g , 'read', 'write', 'admin') @returns hook function / export const verifyscope = (resourcetype string, permission string) => { return async (context hookcontext) => { // check if the user is authenticated if (!context params user) { throw new notauthenticated('you must be authenticated'); } const userid = context params user id; // skip for super admins if (context params user isadmin) { return context; } // construct the required scope const requiredscope = `${resourcetype} ${permission}`; // get the user's scopes const userscopes = await context app service('scopes') find({ query { userid, active true } }); // check if the user has the required scope const hasscope = userscopes data some(scope => scope type === requiredscope || scope type === `${resourcetype}\ admin` ); if (!hasscope) { throw new forbidden(`missing required scope ${requiredscope}`); } return context; }; }; this hook checks if the user is authenticated skips permission checking for super admins constructs the required scope from resource type and permission retrieves the user's scopes from the database checks if the user has the required scope or an admin scope throws an error if the user lacks the necessary permission identity provider model the identity provider model manages user authentication methods // simplified from src/user/identity provider/identity provider model ts import { knex } from 'knex'; / creates the identity provider table @param knex knex client / export async function up(knex knex) promise\<void> { await knex schema createtable('identity provider', table => { // primary key table uuid('id') primary(); // user relationship table uuid('userid') notnullable(); table foreign('userid') references('id') intable('user'); // provider information table string('type') notnullable(); // 'local', 'google', 'github', etc table string('providerid') nullable(); // id from the provider // authentication details table string('email') nullable(); table string('password') nullable(); // hashed password for local auth // oauth tokens table string('accesstoken') nullable(); table string('refreshtoken') nullable(); // status table boolean('active') defaultto(true); // timestamps table timestamp('createdat') defaultto(knex fn now()); table timestamp('updatedat') defaultto(knex fn now()); // indexes table index(\['userid', 'type']); table index(\['type', 'providerid']); table index(\['email']); }); } this model stores authentication information for users supports multiple authentication methods per user manages oauth tokens and local passwords tracks the status and creation of authentication methods scope model the scope model manages user permissions // simplified from src/user/scope/scope model ts import { knex } from 'knex'; / creates the scope table @param knex knex client / export async function up(knex knex) promise\<void> { await knex schema createtable('scope', table => { // primary key table uuid('id') primary(); // user relationship table uuid('userid') notnullable(); table foreign('userid') references('id') intable('user'); // scope information table string('type') notnullable(); // e g , 'project\ read', 'user\ admin' // status table boolean('active') defaultto(true); // timestamps table timestamp('createdat') defaultto(knex fn now()); table timestamp('updatedat') defaultto(knex fn now()); // indexes table index(\['userid', 'type']); table index(\['type']); }); } this model stores permission scopes for users uses a format of resourcetype\ permission for scope types tracks the status and creation of scopes enables efficient querying of user permissions authentication workflow the complete authentication workflow follows this sequence sequencediagram participant client participant authservice as authentication service participant strategy as auth strategy participant identityprovider as identity provider service participant user as user service client >>authservice post /authentication (credentials) authservice >>strategy authenticate(credentials) alt local strategy strategy >>identityprovider find user by email identityprovider >>strategy return identity provider strategy >>strategy verify password hash else oauth strategy strategy >>strategy verify oauth token with provider strategy >>identityprovider find or create identity end strategy >>user get user details user >>strategy return user strategy >>strategy generate jwt strategy >>authservice return authentication result authservice >>client return jwt and user info note over client,authservice for subsequent requests client >>authservice request with jwt in header authservice >>strategy verify jwt strategy >>strategy validate signature and expiration strategy >>user get user details user >>strategy return user strategy >>authservice return authenticated user this diagram illustrates the client sends credentials to the authentication service the appropriate strategy authenticates the credentials the strategy retrieves or creates an identity provider record the strategy generates a jwt for the authenticated user the client uses the jwt for subsequent requests the jwt is verified and the user is retrieved for each request authorization workflow the complete authorization workflow follows this sequence sequencediagram participant client participant service as protected service participant authhook as authentication hook participant scopehook as scope verification hook participant scopeservice as scope service client >>service request with jwt in header service >>authhook process request authhook >>authhook verify jwt authhook >>authhook extract user id authhook >>service add user to context service >>scopehook check permission scopehook >>scopeservice get user scopes scopeservice >>scopehook return scopes alt has required scope scopehook >>service allow request service >>service execute service method service >>client return result else missing required scope scopehook >>client return 403 forbidden end this diagram illustrates the client sends a request with a jwt to a protected service the authentication hook verifies the jwt and adds the user to the context the scope verification hook checks if the user has the required permission if the user has the required scope, the service method executes if the user lacks the required scope, a 403 forbidden error is returned integration with other components the authentication and authorization system integrates with several other components of the server core hooks authentication and authorization are implemented as hooks // example of hook integration in a service import { authenticate } from ' / /hooks/authenticate'; import { verifyscope } from ' / /hooks/verify scope'; // in project hooks ts export default { before { all \[ authenticate ], find \[ verifyscope('project', 'read') ], get \[ verifyscope('project', 'read') ], create \[ verifyscope('project', 'write') ], update \[ verifyscope('project', 'write') ], patch \[ verifyscope('project', 'write') ], remove \[ verifyscope('project', 'admin') ] } }; this integration applies authentication to all service methods specifies required permissions for each method creates a clear security policy for the service leverages the hook system for consistent security enforcement application configuration the authentication system uses configuration values // example of configuration integration import config from ' / /appconfig'; // in authentication ts const authservice = new authenticationservice(app); // configure jwt strategy authservice register('jwt', new jwtstrategy({ jwtoptions config authentication jwtoptions, secret config authentication secret })); // configure local strategy authservice register('local', new localstrategy({ usernamefield config authentication local usernamefield, passwordfield config authentication local passwordfield })); this integration uses configuration values for authentication settings applies jwt options from configuration configures local authentication fields enables environment specific authentication settings services authentication interacts with various services // example of service integration import { notauthenticated } from '@feathersjs/errors'; // in authenticate ts // get the user from the jwt payload const userid = context params payload userid; // retrieve the full user object try { const user = await context app service('users') get(userid); context params user = user; } catch (error) { throw new notauthenticated('user not found'); } this integration uses the user service to retrieve user information accesses the identity provider service for authentication queries the scope service for permission checking creates a cohesive security system across services benefits of authentication & authorization the authentication & authorization component provides several key advantages security protects sensitive data and functionality from unauthorized access flexibility supports multiple authentication methods (local, oauth, api keys) granularity enables fine grained permission control through scopes statelessness uses jwts to maintain sessions without server side storage consistency applies uniform security policies across all services auditability tracks authentication and authorization activities scalability works efficiently in distributed and high load environments these benefits make authentication and authorization essential components for creating secure and reliable applications next steps with an understanding of how the system secures access to resources, the next chapter explores how it enables real time communication between the server and clients next real time communication (primus) docid\ bd0hjk3bfs97clrkxqn97