Learn how to set up user authentication in Sonamu. Sonamu provides an integrated authentication system based on better-auth .
Authentication System Overview
better-auth Integration Proven authentication library Email/password, Social login
Auto Entity Generation Generate entities via CLI User, Session, Account, Verification
Context Based User info per request Sonamu.getContext()
Guards System Declarative permission control @api guards option
Quick Start
1. Generate Auth Entities
Automatically generate entities required by better-auth:
pnpm sonamu auth generate
This command generates 4 entities:
Entity Table Description User users User info (id, name, email, email_verified, image) Session sessions Session info (id, token, expires_at, user_id) Account accounts Social account linking (id, provider_id, access_token, user_id) Verification verifications Email verification etc. (id, identifier, value, expires_at)
If entities already exist, only missing fields are added. Fields with changed types are automatically updated.
2. Run Migrations
After generating entities, run migrations:
pnpm sonamu migrate generate
pnpm sonamu migrate run
Enable authentication in sonamu.config.ts:
// sonamu.config.ts
import type { SonamuConfig } from "sonamu" ;
export default {
// ... other settings
server: {
auth: {
emailAndPassword: { enabled: true },
},
} ,
} satisfies SonamuConfig ;
This enables basic email/password authentication.
API Endpoints
API endpoints provided by better-auth are automatically registered:
Path Method Description /api/auth/sign-up/emailPOST Email signup /api/auth/sign-in/emailPOST Email login /api/auth/sign-outPOST Logout /api/auth/get-sessionGET Get current session
Accessing User Info in Context
Access authenticated user information through Context:
import { Sonamu } from "sonamu" ;
class UserModelClass extends BaseModel {
@ api ({ httpMethod: "GET" , guards: [ "user" ] })
async me () : Promise < UserSubsetA | null > {
const { user , session } = Sonamu . getContext ();
if ( ! user ) return null ;
// Access user.id, user.email, user.name, etc.
return this . findById ( "A" , user . id );
}
}
AuthContext Type
type AuthContext = {
/** Currently logged in user (null if unauthenticated) */
user : User | null ;
/** Current session info (null if unauthenticated) */
session : Session | null ;
};
User and Session types are provided by better-auth.
Access Control with Guards
Basic Guard Usage
class UserModelClass extends BaseModel {
// Login required
@ api ({ httpMethod: "GET" , guards: [ "user" ] })
async getProfile () {
const { user } = Sonamu . getContext ();
return { userId: user . id };
}
// Admin permission required
@ api ({ httpMethod: "DELETE" , guards: [ "admin" ] })
async deleteUser ( id : string ) {
// Only admins can execute
}
}
Implementing guardHandler
Guard logic is implemented in guardHandler in sonamu.config.ts:
// sonamu.config.ts
import { Sonamu } from "sonamu" ;
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
},
apiConfig: {
guardHandler : ( guard , request , api ) => {
const { user } = Sonamu . getContext ();
switch ( guard ) {
case "user" :
if ( ! user ) {
throw new Error ( "Login required" );
}
break ;
case "admin" :
// Need to add role field to User entity
if ( ! user || ( user as any ). role !== "admin" ) {
throw new Error ( "Admin access only" );
}
break ;
case "query" :
// Allow all users
break ;
}
},
},
} ,
} satisfies SonamuConfig ;
Social Login Setup
Google Login
// sonamu.config.ts
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
socialProviders: {
google: {
clientId: process . env . GOOGLE_CLIENT_ID ! ,
clientSecret: process . env . GOOGLE_CLIENT_SECRET ! ,
},
},
},
} ,
} satisfies SonamuConfig ;
GitHub Login
// sonamu.config.ts
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process . env . GITHUB_CLIENT_ID ! ,
clientSecret: process . env . GITHUB_CLIENT_SECRET ! ,
},
},
},
} ,
} satisfies SonamuConfig ;
Adding User Roles
The default User entity in better-auth doesnβt have a role field. If you need role-based authentication, add it directly to the User entity:
1. Add Field in Sonamu UI
Add role field to User entity:
Name: role
Type: string
Default: "user"
2. Add Enum (Optional)
{
"enums" : {
"UserRole" : {
"user" : "Regular user" ,
"admin" : "Administrator" ,
"manager" : "Manager"
}
}
}
3. Check Role in guardHandler
guardHandler : ( guard , request , api ) => {
const { user } = Sonamu . getContext ();
if ( guard === "admin" ) {
if ( ! user || ( user as any ). role !== "admin" ) {
throw new Error ( "Admin permission required" );
}
}
},
Client Integration
Using in React
import { createAuthClient } from "better-auth/react" ;
export const authClient = createAuthClient ({
baseURL: "http://localhost:4000/api/auth" ,
});
// Sign up
await authClient . signUp . email ({
email: "user@example.com" ,
password: "password123" ,
name: "John Doe" ,
});
// Sign in
await authClient . signIn . email ({
email: "user@example.com" ,
password: "password123" ,
});
// Sign out
await authClient . signOut ();
// Get current session
const session = await authClient . getSession ();
Field Mapping
better-auth uses camelCase, but Sonamu uses snake_case. The following fields are automatically mapped:
better-auth Sonamu emailVerifiedemail_verifiedcreatedAtcreated_atuserIduser_idexpiresAtexpires_at
Checklist
Things to verify after setting up authentication:
Next Steps