🔐 Better-Auth plugin for ObjectStack - A battery-included authentication and identity layer for the ObjectStack ecosystem.
- Storage Agnostic: Uses ObjectQL as the storage adapter, meaning authentication data can live in Postgres, Redis, or even Excel files
- Type Safe: End-to-end typed session objects with TypeScript
- RBAC Integration: Automatic permission injection from ObjectOS into session objects
- React Hooks: Pre-built hooks for easy client-side integration
- Framework Agnostic: Works with any JavaScript framework
pnpm add @objectstack/plugin-auth better-authimport { createAuthPlugin } from '@objectstack/plugin-auth';
import { createQLClient } from '@objectstack/ql';
// Initialize ObjectQL client
const ql = createQLClient({
driver: 'postgres', // or 'redis', 'excel', etc.
connection: process.env.DATABASE_URL,
});
// Create auth plugin
const authPlugin = createAuthPlugin({
secret: process.env.BETTER_AUTH_SECRET,
baseURL: process.env.BETTER_AUTH_URL,
// RBAC Integration: Inject permissions into session
onGetPermissions: async (userId) => {
return await os.getPermissions(userId);
},
// Optional: Configure email/password auth
emailProvider: {
enabled: true,
sendVerificationEmail: async ({ user, url }) => {
// Send email logic
},
},
// Optional: Configure social providers
socialProviders: [
{
id: 'google',
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
],
});
// Enable the plugin
await authPlugin.onEnable({
ql,
app: yourExpressApp, // or any compatible server
});import { useSession, usePermissions, signIn, signOut } from '@objectstack/plugin-auth';
function App() {
const { data: session, isPending } = useSession();
const { permissions } = usePermissions();
if (isPending) return <div>Loading...</div>;
if (!session) {
return (
<button onClick={() => signIn.email({
email: 'user@example.com',
password: 'password'
})}>
Sign In
</button>
);
}
return (
<div>
<p>Welcome, {session.user.name}!</p>
<p>Email: {session.user.email}</p>
<p>Permissions: {permissions?.join(', ')}</p>
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}The plugin implements a custom Better-Auth adapter that maps all CRUD operations to ObjectQL entities:
// Example: Creating a user
const user = await ql.entity('User').create({
data: {
email: 'user@example.com',
name: 'John Doe',
},
});This means if ObjectQL is configured with an Excel driver, new users will be written as rows in an Excel file!
The plugin defines authentication entities in GraphQL:
type User {
id: ID!
email: String!
emailVerified: Boolean!
name: String
image: String
createdAt: DateTime!
updatedAt: DateTime!
}
type Session {
id: ID!
userId: ID!
expiresAt: DateTime!
token: String!
# ... more fields
}The plugin bridges Better-Auth (authentication) with ObjectOS (authorization):
// In server config
onGetPermissions: async (userId) => {
// Query ObjectOS for permissions
return await os.getPermissions(userId);
}
// In client
const { permissions } = usePermissions();
// permissions are automatically available in sessionCreates the auth plugin instance.
Options:
secret- Secret key for signing tokensbaseURL- Base URL for auth endpointstrustedOrigins- Array of trusted origins for CORSemailProvider- Email provider configurationsocialProviders- Array of social provider configsonGetPermissions- Callback to get user permissions
Low-level API to create Better-Auth server instance.
Extract session from HTTP request.
React hook to get current session.
const { data: session, isPending, error } = useSession();React hook to get user permissions.
const { permissions, isPending, isAuthenticated } = usePermissions();Check if user has a specific permission.
const { hasPermission, isPending } = useHasPermission('admin.write');Sign in methods for different providers.
// Email/password
await signIn.email({ email, password });
// Social
await signIn.social({ provider: 'google' });Sign out the current user.
await signOut();BETTER_AUTH_SECRET=your-secret-key-min-32-chars
BETTER_AUTH_URL=http://localhost:3000
NODE_ENV=developmentsrc/
├── adapter/
│ └── index.ts # ObjectQL Adapter implementation
├── schema/
│ └── auth.gql # GraphQL schema definitions
├── client/
│ └── hooks.ts # React hooks
├── server/
│ └── index.ts # Server-side initialization
└── index.ts # Main entry point
MIT
Contributions are welcome! Please read our contributing guidelines first.
For issues and questions, please open an issue on GitHub.