# `type.auth_public_principal`

A route that anyone may call, with `authentication: RouteAuthentication.none`, passes on the signed-in caller, though it never looks for one.

Area 8, [Sign-in and identity](/docs/identity.md); not declinable; the next step is usually the human's.

## Why Jadpo refuses it

`authentication: RouteAuthentication.none` lets anyone call a route, and
the route doesn't look for a session or token. So it never knows who is
calling, and `current_principal`, the signed-in caller, has nothing in
it. A query or action that takes a caller would be handed nobody.

Jadpo won't choose the fix for you. Either callers sign in, so the route
knows who they are, or the route stays open and stops depending on who
is calling, and that decides who can reach the data it reads.

## What it looks like

main.jadpo:

```jadpo
principal {
    user: {
        subject: Member.handle
    }
}

authentication {
    browser_session: {
        cookie: "session"
    }
}

type Handle = Text {
    max_length: 40
}

entity Member {
    id: Uuid
    handle: Handle {
        unique: true
    }
}

type MemberView = Output {
    handle: Handle
}

type MemberNotFound = Failure {
    kind: FailureKind.not_found
}

query whoami(caller: Principal.user) fails MemberNotFound -> MemberView {
    from: Member
    where: Member.id == caller.id
    missing: MemberNotFound
}

routes Members {
    prefix: /members

    GET /me {
        authentication: RouteAuthentication.none
        output: MemberView
        run: whoami(current_principal.user)
    }
}
```

```text
error: A route anyone may call passes `current_principal`
 --> main.jadpo:44:21
   |
44 |         run: whoami(current_principal.user)
   |                     ^^^^^^^^^^^^^^^^^ no one is signed in here
  reason: `authentication: RouteAuthentication.none` reads no credential, so the route has no caller to pass on, and nothing it runs may use one.
  next: Remove `authentication: RouteAuthentication.none` so callers sign in, or stop passing `current_principal` (human)
  rule: type.auth_public_principal
  help: https://jadpo.dev/docs/errors/type.auth_public_principal

check failed: 1 error, 1 file
```

`(human)` at the end of the `next:` line tells your coding agent to stop
and ask you which fix you want, because the choice is yours to make: it
decides whether people must sign in to read a member.

## How to fix it

The question is whether the route is about who is calling.

**If it is, so callers must sign in**, remove the
`authentication: RouteAuthentication.none` line. `whoami` reads a
`Member`, so `Member` also needs a grant that lets each person read their
own record:

```jadpo
    GET /me {
        output: MemberView
        run: whoami(current_principal.user)
    }
```

```jadpo
    policy: {
        read: [id]
    }
```


`GET /members/me` now needs a session cookie, and answers each caller
with their own handle. A request without a valid session gets 401.

**If anyone may read a member, signed in or not**, keep the route open and
name the member in the path instead of taking the caller. Its query finds
the member by `id`, and `Member` grants `read` to `Access.public`:

```jadpo
query find_member(member_id: Member.id) fails MemberNotFound -> MemberView {
    from: Member
    where: Member.id == member_id
    missing: MemberNotFound
}
```

```jadpo
    GET /{member_id: Member.id} {
        authentication: RouteAuthentication.none
        output: MemberView
        run: find_member(member_id)
    }
```

```jadpo
    policy: {
        read: [Access.public]
    }
```


`GET /members/{member_id}` answers anyone with that member's handle, and
never knows who is asking.

## Related

- [Open to anyone: `RouteAuthentication.none`](/docs/routes-signed-in-by-default.md#open-to-anyone-routeauthenticationnone)
- [Who is calling: `current_principal`](/docs/who-is-calling-current-principal.md)
- [Anyone signed in, or anyone](/docs/anyone-signed-in-or-anyone.md)
- [A user field on the record](/docs/a-user-field-on-the-record.md)
