Quick Start: Testing Authentication with the SDK¶
This guide will help you test the new JWT authentication system end-to-end using the Foundry SDK.
Prerequisites¶
- .NET 10 SDK installed
- Node.js 18+ and pnpm installed
- PostgreSQL running (via Aspire or standalone)
Step 1: Start the Backend¶
Wait for the Aspire dashboard to start. The API will be available at http://localhost:5000.
Step 2: Create a Test User¶
You need a user account to test login. There are several ways to create one:
Option A: Use User Seeding (Recommended for Testing)¶
Create create-test-user.py in the repo root:
import asyncio
from foundry_sdk import FoundryClient, FoundryClientConfig
from foundry_sdk.modules.core.imports import user_seeding
async def create_user():
# Note: For user seeding, you'll need an admin token or service account
# For now, create the user directly in the database or use the backend endpoints
client = FoundryClient(FoundryClientConfig(
base_url='http://localhost:5000'
))
# If you have an admin token, use this:
# client.config.auth_token = 'your-admin-token'
result = await client.import_data('UserSeedingImport', user_seeding(
enabled=True,
skip_if_users_exist=False,
users=[{
'email': 'test@example.com',
'display_name': 'Test User',
'password': 'TestPassword123!', # Add this field to the import contract
'roles': ['Member']
}]
))
print(f"User created: {result.success}")
asyncio.run(create_user())
Option B: Create User via SQL (Quick and Easy)¶
-- Connect to PostgreSQL
-- Database: foundry_dev (or your configured database)
INSERT INTO mt_doc_user_contract (id, data, mt_last_modified)
VALUES (
gen_random_uuid(),
'{
"Id": "' || gen_random_uuid()::text || '",
"Email": "test@example.com",
"DisplayName": "Test User",
"PasswordHash": "$2a$11$X8K9yZQQwVfR5vGqJKL.1eYJxRXY7FZhPZ8yGKL.1eYJxRXY7FZhP",
"Roles": ["Member"],
"IsActive": true,
"CreatedAt": "' || NOW()::text || '"
}'::jsonb,
NOW()
);
Note: The password hash above is for password123. You'll need to generate proper password hashes in production.
Option C: Use the Backend CreateUser Command (Best Practice)¶
This requires authentication setup, which is what we're testing, so skip this for now.
Step 3: Set Up Environment Variables¶
For foundry-web¶
Edit .env:
Step 4: Start foundry-web¶
The app will be available at http://localhost:5173.
Step 5: Test Login¶
- Navigate to
http://localhost:5173/login - Enter credentials:
- Email:
test@example.com - Password:
password123(or whatever you set) - Click "Sign in"
Expected Behavior:¶
Success:
- You should be redirected to / (home page)
- Check browser console: Should see no errors
- Check localStorage: Should see foundry_access_token and foundry_refresh_token
- Check Network tab: Should see POST to /auth/login with 200 response
Failure: - 401 Unauthorized: Check username/password - CORS error: Check backend CORS configuration - Network error: Check backend is running - 500 Server error: Check backend logs in Aspire dashboard
Step 6: Test Token Refresh (Optional)¶
Open browser console after successful login:
// Get the auth store
const auth = window.__FOUNDRY_AUTH_STORE__;
// Wait for token to expire (default: 60 seconds)
console.log('Waiting 65 seconds for token to expire...');
await new Promise(resolve => setTimeout(resolve, 65000));
// Try to use an authenticated endpoint
// The SDK should automatically refresh the token
const result = await auth.client.getCurrentUser();
console.log('Token auto-refreshed!', result);
Step 7: Test with Python SDK (Optional)¶
Create test-login.py:
import asyncio
from foundry_sdk import FoundryClient, FoundryClientConfig, FoundryError
async def test_login():
client = FoundryClient(FoundryClientConfig(
base_url='http://localhost:5000',
auto_refresh=True
))
try:
# Login
print('Logging in...')
result = await client.login('test@example.com', 'password123')
print(f'Login successful!')
print(f' User: {result.user.email}')
print(f' Roles: {result.user.roles}')
print(f' Token expires in: {result.expires_in} seconds')
# Test authenticated endpoint
print('\nGetting current user...')
user = await client.get_current_user()
print(f'Current user: {user.email}')
# Logout
print('\nLogging out...')
await client.logout()
print('Logged out successfully')
except FoundryError as e:
print(f'Error: {e}')
if e.status_code:
print(f' Status code: {e.status_code}')
asyncio.run(test_login())
Run it:
Troubleshooting¶
Login Returns 401 Unauthorized¶
Check:
1. User exists in database
2. Password is correct
3. Backend is running (dotnet run in AspireHost)
4. Check backend logs in Aspire dashboard
Fix:
# Verify backend is running
curl http://localhost:5000/health
# Check user exists
# Connect to PostgreSQL and run:
SELECT data->>'Email', data->>'DisplayName'
FROM mt_doc_user_contract
WHERE data->>'Email' = 'test@example.com';
CORS Errors in Browser¶
Check: Backend CORS configuration in src/Aspire/LBS.AspireHost/Program.cs
Fix: Ensure CORS allows http://localhost:5173:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins("http://localhost:5173")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
// Later in the file
app.UseCors();
SDK Not Found in foundry-web¶
Check:
Fix:
# Rebuild SDK
cd sdk/typescript
pnpm install
pnpm build
# Link to foundry-web
pnpm link --global
cd ../../src/Apps/foundry-web
pnpm link --global @luckboxstudios/foundry-sdk
pnpm dev
Token Refresh Not Working¶
Check:
1. autoRefresh: true in FoundryClient config (default)
2. Refresh token is stored in localStorage
3. Backend /auth/refresh endpoint is working
Test:
Fix: Check backend logs for refresh endpoint errors.
Database Connection Errors¶
Check: PostgreSQL is running
Fix:
# If using Aspire
dotnet run # Aspire will start PostgreSQL container
# If standalone
docker run --name foundry-postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres:16
Next Steps¶
Once authentication is working:
- Add Protected Routes: Create a route guard to redirect unauthenticated users to login
- Add Logout Button: Add logout functionality to your app header/menu
- Test Token Expiration: Verify auto-refresh works after 60 seconds
- Add Role-Based Access: Check
user.rolesfor authorization - Create More Users: Add user management UI or import script
Additional Resources¶
- SDK Local Development Guide - Complete SDK setup guide
- TypeScript SDK README - Full SDK documentation
- Python SDK README - Python SDK documentation
- Security Guide - Authentication and authorization details
Success Criteria¶
You should be able to: - Log in with email and password - See user info in browser console/localStorage - Make authenticated API calls - Logout successfully - Auto-refresh expired tokens
If all of these work, your authentication setup is complete!