Amphora Authentication Adapter
amphora-auth serves as an authentication adapter specifically designed for the Amphora content management system, providing robust user authentication capabilities within the Clay ecosystem. It facilitates both local username/password authentication and seamless integration with a variety of third-party OAuth providers, including Google, Twitter, Slack, Cognito, and LDAP. This broad support enables flexible and secure authentication strategies for applications built on the Clay platform. The current stable version is 2.1.0. While a specific release cadence isn't explicitly stated, updates likely align with developments in the broader Clay platform. Its primary differentiator is its deep, opinionated integration with Amphora and Clay, which significantly simplifies the setup and management of diverse authentication backends for Clay-based applications, streamlining security configuration.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'get') or storage.get is not a function
cause The `storage` parameter passed to `amphoraAuth` is not a valid DB instance or lacks the required `get` and `put` methods.fixEnsure the `storage` object passed during initialization conforms to the expected interface with `get` and `put` methods, typically an Amphora storage instance. -
Error: Missing environment variable for [ProviderName] provider
cause An authentication provider (e.g., Google, Twitter) is configured, but its corresponding environment variables (consumer key, secret, etc.) are not set.fixSet the required environment variables for the specified provider (e.g., `export GOOGLE_CONSUMER_KEY='your_key'`) in the environment where the application runs. -
Error: Failed to fetch user data for [username]
cause The user account does not exist in the database or the `user.yml` import was incorrect/incomplete, or the specified provider doesn't match the imported user's provider.fixVerify the user exists in your Clay instance and that their `username` and `provider` in `user.yml` (and thus in the database) match the login attempt. Re-import the `user.yml` if necessary. -
Error: Passport session setup requires a session store.
cause The Express session middleware is not correctly configured with a session store before `amphora-auth` is initialized, or `connect-redis` is not properly set up.fixEnsure `express-session` is initialized with a `store` (e.g., `RedisStore`) and mounted on the Express app *before* `amphora-auth` is called, and that `redis` and `connect-redis` are correctly configured.
Warnings
- gotcha Missing or incorrectly configured environment variables for authentication providers will prevent users from authenticating via those methods. Each provider (Google, Twitter, Slack, Cognito, LDAP) requires specific `_CONSUMER_KEY`, `_CONSUMER_SECRET`, and potentially other variables to be exported.
- breaking The `clayhandlebars` package is a peer dependency, specifically requiring version `5`. Mismatches with other versions of `clayhandlebars` or its absence can lead to runtime errors, particularly in template rendering related to authentication pages.
- gotcha Setting the `MAINTENANCE_MODE_ENABLED` environment variable to `true` will prevent all users from entering edit mode or making any edits, redirecting them to a login page with a maintenance message. This can be enabled even if users were already in an editing session.
- gotcha User accounts must be imported correctly using `claycli` with a `user.yml` file. Incorrect `username`, `provider`, `password`, or `auth` roles will result in failed login attempts, even if provider configurations are otherwise correct.
Install
-
npm install amphora-auth -
yarn add amphora-auth -
pnpm add amphora-auth
Imports
- amphoraAuth
import { amphoraAuth } from 'amphora-auth'; const amphoraAuth = require('amphora-auth');import amphoraAuth from 'amphora-auth';
- AuthService
const { AuthService } = require('amphora-auth');import { AuthService } from 'amphora-auth';
Quickstart
import amphoraAuth from 'amphora-auth';
import express from 'express';
import redis from 'redis';
import session from 'express-session';
import connectRedis from 'connect-redis';
const app = express();
const router = express.Router();
const RedisStore = connectRedis(session);
// Dummy implementations for required parameters
const providers = {
google: {
// In a real app, these would come from env vars
consumerKey: process.env.GOOGLE_CONSUMER_KEY ?? '',
consumerSecret: process.env.GOOGLE_CONSUMER_SECRET ?? ''
}
// ... other providers like twitter, slack, cognito, ldap
};
const redisClient = redis.createClient();
const store = new RedisStore({ client: redisClient });
const site = { slug: 'my-site', host: 'localhost:3001' }; // Example site metadata
const storage = {
get: () => Promise.resolve({ data: {} }),
put: () => Promise.resolve({})
}; // Mock DB instance
const bus = {
publish: () => {},
subscribe: () => {}
}; // Mock Redis bus instance
// Initialize auth module
amphoraAuth({
router, // Site router for auth routes
providers, // Authentication providers configuration
store, // Redis Session Store for sessions
site, // Site metadata
storage, // DB instance for user storage
bus // Redis bus instance for inter-process communication
});
app.use(session({
store: store,
secret: 'supersecretkey',
resave: false,
saveUninitialized: false,
cookie: { secure: false } // Set to true in production with HTTPS
}));
app.use(router);
app.get('/', (req, res) => {
res.send('Amphora Auth is running!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});