Github|...

Authentication

Authentication in Spooky is built directly into the sql schema, making it robust, typesafe, and dynamic. Because access control is defined at the database layer, your rules are consistently enforced regardless of how the data is accessed.

Schema Configuration

You define authentication using DEFINE ACCESS. This allows you to specify exactly how users sign up and sign in, and what permissions they have.

sql
-- Define access scope for accounts
DEFINE ACCESS account ON DATABASE TYPE RECORD
SIGNUP ( 
  CREATE user 
  SET username = $username,
    password = crypto::argon2::generate($password)
)
SIGNIN (
  SELECT * FROM user 
  WHERE username = $username 
    AND crypto::argon2::compare(password, $password)
)
DURATION FOR TOKEN 15m, FOR SESSION 30d;

-- Permissions use the $auth variable to check the current user
DEFINE TABLE user SCHEMAFULL
PERMISSIONS
FOR update, delete WHERE id = $auth.id
FOR select, create WHERE true;

Client-Side Authentication

Spooky provides a strongly-typed authentication service on the client. It integrates seamlessly with the schema definitions.

Sign In

TypeScript
import { db } from './db';

// The second argument is typesafe based on your SIGNIN definition
await db.auth.signIn('account', {
username: 'spooky_user',
password: 'secure_password'
});

Sign Up

TypeScript
import { db } from './db';

await db.auth.signUp('account', {
username: 'new_user',
password: 'secure_password'
});

Sign Out

TypeScript
await db.auth.signOut();

Reacting to Auth State

You can subscribe to authentication state changes to update your UI dynamically. The callback receives the user ID when authenticated, or null when signed out.

TypeScript
import { createSignal, onCleanup } from 'solid-js';

function MyComponent() {
const [userId, setUserId] = createSignal<string | null>(null);

// Subscribe to auth state changes
const unsubscribe = db.auth.subscribe((uid) => {
  setUserId(uid);
  if (uid) {
    console.log('User logged in:', uid);
  } else {
    console.log('User logged out');
  }
});

// Clean up subscription
onCleanup(() => unsubscribe());

return <div>User ID: {userId() || 'Not logged in'}</div>;
}

Third-Party Providers

Clerk

Note Integration coming soon.

Firebase

Note Integration coming soon.

Auth0

Note Integration coming soon.