> ## Documentation Index
> Fetch the complete documentation index at: https://docs.edgespark.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Path-based auth in EdgeSpark

> EdgeSpark enforces authentication through route prefixes: /api/* requires login, /api/public/* is optional, and /api/webhooks/* skips auth.

EdgeSpark enforces authentication through URL path conventions. There is no auth middleware for you to register. The route prefix determines the behavior.

## The three path conventions

| Path pattern      | Authentication behavior                                                              |
| ----------------- | ------------------------------------------------------------------------------------ |
| `/api/*`          | Login required. Requests without a valid session are rejected with `401`.            |
| `/api/public/*`   | Login optional. `auth.user` is populated if the user is logged in, otherwise `null`. |
| `/api/webhooks/*` | No session-based auth. Verify incoming requests yourself.                            |

## Protected routes

```typescript server/src/index.ts theme={null}
import { db } from "edgespark";
import { auth } from "edgespark/http";
import { Hono } from "hono";
import { posts } from "@defs";

const app = new Hono()
  .get("/api/profile", (c) => {
    return c.json({ email: auth.user.email, id: auth.user.id });
  })
  .post("/api/posts", async (c) => {
    const body = await c.req.json<{ title: string }>();

    await db.insert(posts).values({
      title: body.title,
      authorId: auth.user.id,
    });

    return c.json({ created: true }, 201);
  });

export default app;
```

## Public routes

```typescript server/src/index.ts theme={null}
import { db } from "edgespark";
import { auth } from "edgespark/http";
import { Hono } from "hono";
import { posts } from "@defs";

const app = new Hono().get("/api/public/posts", async (c) => {
  const rows = await db.select().from(posts);

  if (auth.user) {
    return c.json({ posts: rows, currentUserId: auth.user.id });
  }

  return c.json({ posts: rows });
});

export default app;
```

## Webhook routes

```typescript server/src/index.ts theme={null}
import { secret } from "edgespark";
import { Hono } from "hono";

const app = new Hono().post("/api/webhooks/stripe", async (c) => {
  const rawBody = await c.req.text();
  const signingSecret = secret.get("STRIPE_WEBHOOK_SECRET") ?? "";

  return c.json({
    received: true,
    hasSigningSecret: Boolean(signingSecret),
    size: rawBody.length,
  });
});

export default app;
```

<Warning>
  Webhook routes have no platform-level session authentication. Always verify signatures or shared secrets from the sender. See [Authenticate users](/guides/authentication) for a full verification example.
</Warning>

## See also

<Columns cols={2}>
  <Card title="Authenticate users" icon="lock" href="/guides/authentication">
    How to read the current user and verify incoming webhooks.
  </Card>

  <Card title="auth reference" icon="code" href="/sdk/auth">
    The runtime auth API and when `auth.user` is available.
  </Card>
</Columns>
