A complete authentication and user management solution.
- Sign in with Google or with an email and password
- Authorize your users by giving permissions to nested groups
- Authenticate your users on your other APIs using JWT tokens
- Allow specific groups to manage other users through a user interface
- Sendgrid: sends create account and forgot password e-mails
- Google Cloud Firestore: stores accounts and software configuration
- Passwords are hashed before saved
- Email addresses are case-insensitive
- Cookies are protected against forgery using a signature cookie
- Requests from an allowed origin return CORS headers with that origin
- Groups can (optionally) be nested in other groups, forming a hiarchy
- Users get the permissions attached to the groups they are in and the groups nested inside of them
- The group owner property refers to a permission required to add or remove users from that group
- Links are used to sign up and sign in a user when they follow the link from their e-mail client
- Run
npm install
inside both the/api
and/client
folder - Create environment variable files
.env.production
and.env.development
in both the/api
and/client
folder - Add a
google-service.json
file to the/api
folder. You can get this file from Google Cloud Console - Create SSL certificate files in the
/api/ssl
folder. I host my server on Google Cloud Run, and therefore I only need to configure this for local development- Set the
HTTPS_PORT
in the.env.production
and.env.development
files in the/api
folder - On your local machine run
openssl req -new -newkey rsa:4096 -days 9999 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.irrelevant.gg" -keyout privkey.pem -out cert.pem
- On your server run
certbot certonly -d <YOUR_DOMAIN> -m <YOUR_EMAIL> --standalone --no-eff-email --non-interactive --agree-tos
- Put
cert.pem
,privkey.pem
and optionallychain.pem
in theapi/ssl
folder
- Set the
I have added a Dockerfile
for those that want to deploy this application as a container. The client should still be built on your local machine using npm run-script build
before creating and deploying your image.
// Database Objects
type User = {
email: string;
name: string;
groups: string[];
password: string | null;
google: string | null;
picture: string | null;
created: Date;
};
type Group = {
slug: string;
permissions: string[];
owner: string;
parent: string | null;
name: string;
created: Date;
};
type Session = {
id: string;
user: string;
expired: Date | null;
created: Date;
};
type Link = {
id: string;
name: string;
email: string;
password: string | null;
redirect: string;
expired: Date | null;
created: Date;
};
type Email = {
slug: string;
subject: string;
html: string;
text: string;
};
type Configuration = {
slug: string;
value: string;
};
// Response Objects
type KeyResponse = {
type: "key";
key: string;
};
type ErrorResponse = {
type: "error";
status: number;
message: string;
};
type RedirectResponse = {
type: "redirect";
location: string;
};
type SignInResponse = {
type: "sign-in";
token?: string;
groups: string[];
permissions: string[];
email: string;
name: string;
picture: string;
password: boolean;
google: boolean;
};
type LoadResponse = {
type: "load";
ownedGroups: {
slug: string;
parent: string | null;
name: string;
created: Date;
}[];
users: {
email: string;
name: string;
password: boolean;
google: boolean;
picture: string;
groups: string[];
}[];
groups?: Group[];
};
// Request Body
type RequestBody = null | {
name?: string;
email?: string;
groups?: string[];
redirect?: string;
password?: string;
sendEmail?: string;
setGroups?: {
created: string;
slug: string;
permissions: string[];
owner: string;
parent: string;
name: string;
status: string;
}[];
};