Authentication and Authorization
Websites with logins must use built-in auth to handle sessions, cookies, and permissions.
log in
- Websites with login or protected pages should only use Cake20's auth.login, auth.user, auth.require and auth.logout.
- Declare shared first-level access for both pages and /api paths in package.json auth, and do not create a separate login.hook.ts.
- The login screen consists of an independent /login page and auth layout.
- It does not implement its own JWT, session cookie, browser token, or localStorage·store based authentication.
- The user in auth.login(user, maxAge?) requires an id, and if a role check is required, put an array of roles strings.
- Browser login is completed by inserting the returned cookie into the set-cookie header of the response.
- maxAge is an optional lifetime in seconds and cannot exceed the maximum session time set on your website.
- The original password, API Secret, and unnecessary personal information are not included in the session user.
- The token returned by auth is not passed directly to JSON or localStorage.
// server/api/login.post.ts
export const config = {
filter: {
email: z.string().email(),
password: z.string().min(8)
}
};
export default async (data: Input<typeof config.filter>) => {
// verifyPassword is a password hash verification function implemented by the website.
const user = await db.user.findUnique({
where: { email: data.email }
});
if (!user || !await verifyPassword(data.password, user.password)) {
throw Object.assign(new Error("Your login information is incorrect."), {
statusCode: 401
});
}
const login = await auth.login({
id: user.id,
roles: [user.role],
name: user.name
});
return Response.json({
user: { id: user.id, name: user.name, roles: [user.role] }
}, {
headers: { "set-cookie": login.cookie }
});
};Google, GitHub, Naver login
- Enter your provider Client ID and Client Secret in the Social Login tab of your website settings. Enter and register the displayed callback URL with the provider app.
- If you clone a social login website from the template list, you can use Google, GitHub and Naver. You can get started with buttons, login API, and session handling examples.
- The login button is /api/auth/google, /api/auth/github or Just go to /api/auth/naver.
- auth.oauth handles authentication URL, state, PKCE, server token exchange and HttpOnly Handles session creation.
- login(profile) receives a provider-independent OAuthProfile signal and connects the website Returns the user to store in the session.
- OAuthProfile contains provider, id and optional email, emailVerified, Name, username, and avatar are entered.
- Rather than combining user accounts by email alone, store the provider and id combination uniquely.
- Only providers with both Client ID and Secret set are entered in auth.providers.
- next, redirect and error only accept paths starting with / from the current website.
- Cake20 does not store access tokens for logins in the browser or session.
// server/api/auth/[provider].get.ts
const providers = new Set<OAuthProvider>(["google", "github", "naver"]);
export default async (_input: unknown, context: ApiContext) => {
const provider = context.params.provider as OAuthProvider;
if (!providers.has(provider)) {
throw Object.assign(new Error("Unsupported login provider."), {
statusCode: 404
});
}
return auth.oauth(context.request, {
provider,
redirect: "/account",
error: "/login",
async login(profile) {
const user = await findOrCreateUser(profile);
return { id: user.id, roles: [user.role], name: user.name };
}
});
};Current user and permissions
- auth.user(request) returns the current session user, or null if not logged in.
- auth.require(request) throws a 401 error for non-logged in requests.
- auth.require(request, roles) will raise a 403 error if none of the roles you passed in user roles is present.
- To specify the return type as the website user type, use auth.user<MyUser>() and auth.require<MyUser>().
- Browsers automatically send session cookies to other API requests from the same origin, so a separate auth header is not required.
- Editor design mode does not run the website Bun server. It uses app/preview JSON generated from the current rows returned by each *.db.ts seed.
- In Design Preview, where you manually select a protected page, it will retain that selection even if your website code moves it to /login.
- If you select /login, /signin, /sign-in, /auth, or /login page directly, the GET API will return 401 to display the login screen itself.
- POST, PUT, PATCH, and DELETE API requests in design mode are blocked, and actual authentication and data verification are performed in runtime mode.
// server/api/me.get.ts
export default async (_input: unknown, context: ApiContext) => ({
user: await auth.user(context.request)
});
// server/api/admin.get.ts
export default async (_input: unknown, context: ApiContext) => {
const user = await auth.require(context.request, ["admin", "owner"]);
return { user, report: await createReport() };
};log out
- auth.logout(request) deletes the current session on the server.
- Put the returned cookie in set-cookie to remove the browser's cookie as well.
- After logout, the protection API returns 401 on auth.require.
// server/api/logout.post.ts
export default async (_input: unknown, context: ApiContext) => {
const logout = await auth.logout(context.request);
return Response.json({ ok: true }, {
headers: { "set-cookie": logout.cookie }
});
};Storage location and security
- Only random session identifiers are stored in the browser as HttpOnly and SameSite=Lax cookies, and Secure is also applied in operational HTTPS.
- User session data is stored in Redis for each website.
- Session data can be up to 64KB and is maintained within the lifetime of your website settings.
- The session lasts for as long as you set on the website and expires first if there are no requests for 30 minutes.
- auth is for server code such as API, Route, and Event that receive requests, and store is for Cake20 View browser status.
- If you need to log in, call an API that returns the auth.user result, like /api/me. The store optionally stores only user-visible information that is publicly available.