CAKE20

AI Web PaaS

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.