Project Sesame is an open-source demo web application built with Node.js, designed to provide a hands-on environment for web developers to explore, experiment and learn a wide range of identity and authentication features and patterns.
npm cinpm run buildThis command will run the emulator, RP and IdP projects, and Caddy proxy:
npm run dev:localCaddy should proxy from https://rp.localhost to localhost:8080 and https://idp.localhost to localhost:8000,
or other ports that you specify in the rp-localhost.config.json and idp-localhost.config.json config files.
Note
sudo is required to run the Caddy scripts. You may need to enter your password during the command.
For local testing, you can configure Chrome to ignore warnings and errors related to certificates.
- Launch Chrome with the
--ignore-certificate-errorscommand line flag - Enable
chrome://flags/#unsafely-treat-insecure-origin-as-secureand set its contents to:
https://localhost,wss://localhost:3000,https://rp.localhost,wss://rp.localhost,wss://rp.localhost:3000,https://idp.localhost
You can use this code base to try and experiment with new ideas. To add a new sign-in flow, follow the instructions below.
- Determine the path. e.g.
/sign-in - Add a new HTML template under
src/shared/views. e.g.src/shared/views/sign-in.html - Add a TypeScript file under
src/client/pages. e.g.src/client/pages/sign-in.ts. - Layout template is
src/client/layout.html. The partial templates are undersrc/shared/views/partials. - Add a server behavior at
src/server/app.ts. e.g.app.get('/sign-in', pageAclCheck(PageType.SignIn), (req: Request, res: Response)) => { res.render('sign-in.html', { title: 'Password', layout: 'password', }); });
Unless this is a public page, use the pageAclCheck middleware to specify ACL.
export enum PageType {
NoAuth = 0, // No authentication is required
SignUp = 1, // This is a sign-up page
SigningUp = 2, // The user must be signing up
SignIn = 3, // This is a sign-in page
FirstCredential = 4, // The user has provided the username
Reauth = 5, // The user must be signed in and requires reauthentication
SignedIn = 6, // The user must be signed in
Sensitive = 7, // The user must be recently signed in
}The pageAclCheck middleware automatically redirects the user if they need to be signed in to access this page etc.
Unless this is a public API, use the apiAclCheck middleware to specify ACL.
export enum ApiType {
NoAuth = 0, // No authentication is required
PasskeyRegistration = 1, // The user is either signing-up, signed-in or upgrading
SigningUp = 2, // The user is in the middle of signing up
SignIn = 3, // The user is about to sign in with a username and a credential
FirstCredential = 4, // The user is about to sign in
SecondCredential = 5, // The user is about to sign in
SignedIn = 6, // The user must be signed in
Sensitive = 7, // The user must be recently signed in
}The apiAclCheck middleware automatically blocks requests with insuffcient privilege.
Start a session after the user successfully signed in.
Create or use a middleware under src/server/middlewares.
For example, if the you want to check a password at /auth/sign-in, create the
endpoint in src/server/middlewares/auth.ts.
router.post('/sign-in', apiAclCheck(ApiType.Authentication), async (req: Request, res: Response) => {
const {username, password} = req.body;
// TODO: Validate entered parameter.
if (!Users.isValidUsername(username) || !Users.isValidPassword(password)) {
return res.status(401).json({error: 'Enter at least one random letter.'});
}
const user = await Users.validatePassword(username, password);
if (user) {
// Set the user as a signed in status
new SessionService(req.session).setSessionUser(user);
return res.json(user);
} else {
return res.status(401).json({error: 'Failed to sign in.'});
}
});