insightautomate
insightautomate
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
Nice. Do you have any details on how it is likely be implemented?
63 replies
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
In what way does it expose it to abuse? With the right RLS (and CLS if necessary) you can lock things down pretty tightly
63 replies
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
@sebastian the supabase client with RLS allows us to skip out on building an API layer as well as utilising things like realtime (more important for us). To be honest I'm not the biggst fan of the supabase library and might end up switching out to setting up an API with an ORM but the realtime features are more interesting albeit requiring a slightly different setup.
63 replies
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
I think with supabase's recent third-party auth support there is likely a better way to do it via jwt but I haven't dug too deep into that. Hopefully the official integration will do that
63 replies
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
@umang In short this is my initial implementation 1. Create database functions to get/set the current user ID in PostgreSQL session variables:
CREATE FUNCTION current_user_id() RETURNS text AS $$
SELECT current_setting('my.user_id', true);
$$ LANGUAGE sql STABLE;

CREATE FUNCTION set_user_id(user_id text) RETURNS void AS $$
SELECT set_config('my.user_id', user_id, false);
$$ LANGUAGE sql;
CREATE FUNCTION current_user_id() RETURNS text AS $$
SELECT current_setting('my.user_id', true);
$$ LANGUAGE sql STABLE;

CREATE FUNCTION set_user_id(user_id text) RETURNS void AS $$
SELECT set_config('my.user_id', user_id, false);
$$ LANGUAGE sql;
2. Enable RLS on your table and create a policy:
ALTER TABLE horse_accounts ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users see own records"
ON horse_accounts
FOR ALL
USING (created_by = current_user_id());
ALTER TABLE horse_accounts ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users see own records"
ON horse_accounts
FOR ALL
USING (created_by = current_user_id());
3. Create RLS-enabled client utilities that automatically set the user ID:
// Server-side
export const createRlsClient = async (cookieStore: any) => {
const supabase = createClient(cookieStore);
const session = await auth.api.getSession({ headers: await headers() });

if (session?.user?.id) {
await supabase.rpc("set_user_id", { user_id: session.user.id });
}

return supabase;
};

// Client-side
export const createRlsClient = async () => {
const supabase = createClient();
const { data: session } = await betterAuthClient.getSession();

if (session?.user?.id) {
await supabase.rpc("set_user_id", { user_id: session.user.id });
}

return supabase;
};
// Server-side
export const createRlsClient = async (cookieStore: any) => {
const supabase = createClient(cookieStore);
const session = await auth.api.getSession({ headers: await headers() });

if (session?.user?.id) {
await supabase.rpc("set_user_id", { user_id: session.user.id });
}

return supabase;
};

// Client-side
export const createRlsClient = async () => {
const supabase = createClient();
const { data: session } = await betterAuthClient.getSession();

if (session?.user?.id) {
await supabase.rpc("set_user_id", { user_id: session.user.id });
}

return supabase;
};
4. Use the RLS client instead of the standard client for all database queries:
// Instead of createClient(), use:
const supabase = await createRlsClient(cookieStore);
// Instead of createClient(), use:
const supabase = await createRlsClient(cookieStore);
63 replies
BABetter Auth
Created by insightautomate on 5/9/2025 in #help
Hashing script to seed database
which can be called with
import subprocess
import sys

def hash_password(password):
"""
Hash a password using Better Auth's exact implementation via Node.js

Args:
password: The plaintext password to hash

Returns:
Hashed password string in Better Auth format
"""
try:
# Use the full path to node that you provided
node_path = "/Users/myMacBookUsername/.nvm/versions/node/v20.12.2/bin/node"

# Call the Node.js script with the password as an argument
result = subprocess.run(
[node_path, 'hash-password.js', password],
capture_output=True,
text=True,
check=True
)
# Return the output (the hash)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error hashing password: {e.stderr}", file=sys.stderr)
raise
import subprocess
import sys

def hash_password(password):
"""
Hash a password using Better Auth's exact implementation via Node.js

Args:
password: The plaintext password to hash

Returns:
Hashed password string in Better Auth format
"""
try:
# Use the full path to node that you provided
node_path = "/Users/myMacBookUsername/.nvm/versions/node/v20.12.2/bin/node"

# Call the Node.js script with the password as an argument
result = subprocess.run(
[node_path, 'hash-password.js', password],
capture_output=True,
text=True,
check=True
)
# Return the output (the hash)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error hashing password: {e.stderr}", file=sys.stderr)
raise
4 replies
BABetter Auth
Created by insightautomate on 5/9/2025 in #help
Hashing script to seed database
For anyone else who comes across this I solved it by having to run a separate node script that the python references.
// hash-password.js
const { scryptAsync } = require('@noble/hashes/scrypt');
const crypto = require('crypto');

// Configuration matching Better Auth exactly
const config = {
N: 16384,
r: 16,
p: 1,
dkLen: 64,
};

async function generateKey(password, salt) {
return await scryptAsync(password.normalize("NFKC"), salt, {
N: config.N,
p: config.p,
r: config.r,
dkLen: config.dkLen,
maxmem: 128 * config.N * config.r * 2,
});
}

async function hashPassword(password) {
// Generate a random salt (16 bytes) and convert to hex
const salt = crypto.randomBytes(16).toString('hex');
const key = await generateKey(password, salt);
return `${salt}:${Buffer.from(key).toString('hex')}`;
}

// Get the password from command line argument
async function main() {
const password = process.argv[2];
if (!password) {
console.error('Please provide a password as an argument');
process.exit(1);
}

try {
const hash = await hashPassword(password);
console.log(hash); // Output the hash to be captured by Python
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}

main();
// hash-password.js
const { scryptAsync } = require('@noble/hashes/scrypt');
const crypto = require('crypto');

// Configuration matching Better Auth exactly
const config = {
N: 16384,
r: 16,
p: 1,
dkLen: 64,
};

async function generateKey(password, salt) {
return await scryptAsync(password.normalize("NFKC"), salt, {
N: config.N,
p: config.p,
r: config.r,
dkLen: config.dkLen,
maxmem: 128 * config.N * config.r * 2,
});
}

async function hashPassword(password) {
// Generate a random salt (16 bytes) and convert to hex
const salt = crypto.randomBytes(16).toString('hex');
const key = await generateKey(password, salt);
return `${salt}:${Buffer.from(key).toString('hex')}`;
}

// Get the password from command line argument
async function main() {
const password = process.argv[2];
if (!password) {
console.error('Please provide a password as an argument');
process.exit(1);
}

try {
const hash = await hashPassword(password);
console.log(hash); // Output the hash to be captured by Python
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}

main();
4 replies
BABetter Auth
Created by oof2win2 on 2/10/2025 in #help
integrating with postgres rls (supabase)
@bekacru any idea on timings for the supabase integrration? I've just gone through manually implementing RLS via postgres functions and middleware, was not exactly a smooth experience so would be great to see a closer integration.
63 replies