AuthContext is part of Context, providing user authentication state and session information. It is implemented based on better-auth.
Type Definition
import type { Session, User } from "better-auth";
type AuthContext = {
/** Currently logged in user (null if unauthenticated) */
user: User | null;
/** Current session info (null if unauthenticated) */
session: Session | null;
};
Properties
user
Information about the currently authenticated user. null if not logged in.
The User type is provided by better-auth and includes the following fields by default:
type User = {
id: string;
name: string;
email: string;
emailVerified: boolean;
image: string | null;
createdAt: Date;
updatedAt: Date;
};
Usage example:
import { Sonamu } from "sonamu";
class UserModelClass extends BaseModel {
@api({ httpMethod: "GET", guards: ["user"] })
async getMyProfile() {
const { user } = Sonamu.getContext();
if (!user) {
throw new UnauthorizedException("Login required");
}
return {
id: user.id,
email: user.email,
name: user.name,
};
}
}
session
Current session information. null if not logged in.
The Session type is provided by better-auth and includes the following fields:
type Session = {
id: string;
userId: string;
token: string;
expiresAt: Date;
createdAt: Date;
updatedAt: Date;
};
Usage example:
class SessionModelClass extends BaseModel {
@api({ httpMethod: "GET", guards: ["user"] })
async getSessionInfo() {
const { session } = Sonamu.getContext();
return {
sessionId: session.id,
expiresAt: session.expiresAt,
};
}
}
Configuration
To use AuthContext, you need to configure authentication in sonamu.config.ts.
Basic Configuration
// sonamu.config.ts
import type { SonamuConfig } from "sonamu";
export default {
server: {
auth: {
emailAndPassword: { enabled: true },
},
},
} satisfies SonamuConfig;
Adding Social 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;
Access Control with Guards
To require authentication for API methods, you can use the guards option:
class UserModelClass extends BaseModel {
@api({ httpMethod: "GET", guards: ["user"] })
async getMyData() {
const { user } = Sonamu.getContext();
// guards: ["user"] guarantees user is not null
return this.findById("A", user!.id);
}
@api({ httpMethod: "GET", guards: ["admin"] })
async getAllUsers() {
// guards: ["admin"] allows only admins
return this.findMany("A", {});
}
}
Guard handling logic is implemented in guardHandler:
// sonamu.config.ts
import { Sonamu } from "sonamu";
export default {
server: {
apiConfig: {
guardHandler: (guard, request, api) => {
const { user } = Sonamu.getContext();
if (guard === "user" && !user) {
throw new UnauthorizedException("Login required");
}
if (guard === "admin") {
if (!user || (user as any).role !== "admin") {
throw new UnauthorizedException("Admin permission required");
}
}
return true;
},
},
},
} satisfies SonamuConfig;
guardHandler runs inside AsyncLocalStorage, so you can access the current request’s Context via Sonamu.getContext().
Extending User Type
If you’ve added fields to the User entity in your project, you can modify the entity through Sonamu UI. Added fields are accessible on the user object, but type assertions are required for TypeScript type safety:
const { user } = Sonamu.getContext();
// If you added a role field
const userRole = (user as any).role;
// Or use type guards
interface ExtendedUser extends User {
role: "admin" | "user" | "manager";
}
function isExtendedUser(user: User | null): user is ExtendedUser {
return user !== null && "role" in user;
}
if (isExtendedUser(user)) {
console.log(user.role); // Type-safe
}
Authentication Flow
- Client sends login request to
/api/auth/sign-in/email
- better-auth handles authentication and creates session
- Session token is stored in cookie
- Subsequent requests identify user via cookie token
- user/session is injected into Context before API method execution
- Access user info via
Sonamu.getContext()