# [AuthMethod(AuthSlot.X)] — the sign-in slot a method is written for

> `[AuthMethod(AuthSlot.X)]` says which `app.AuthBootstrap` slot a sign-in method is written for. A package that ships sign-in methods but states no bootstrap of its own declares them this way, so an app that forgets one is told the exact line to add — and a method wired into a slot it was not written for is warned. Bare `[AuthMethod]` stays legal.

<!-- id: security-auth-slot · area: security · stability: stable · html: https://osysharp.com/reference/security/auth-slot/ -->

## Summary        {#summary}
An `[AuthMethod]` may name the **slot** of [`app.AuthBootstrap`](https://osysharp.com/reference/security/auth-bootstrap/) it is written for:
`[AuthMethod(AuthSlot.Login)]`, `[AuthMethod(AuthSlot.EmailVerifyCode)]`. Nothing about who may call it changes — the
wiring still decides that ([[security-auth-method#both-ways]]). What changes is what the compiler can **tell you**: a
used package's method your app forgot to wire is reported with the one line that wires it, and a method wired into a
slot it was not written for is reported before anyone signs in through it.

```osy title="a sign-in method that says which slot it fills" test app=security-auth-slot
[Role] enum AppRole { Authenticator, Member }

[Principal]
entity User {
  [Required, Unique, MaxLength(255)] string Email;
  [MaxLength(200)] string PasswordHash;
  security {
    allow read when IsAuthenticated;
    allow read, create when IsAuthenticator;
    deny read PasswordHash when !IsAuthenticator;
  }
}

[RoleGrant] entity RoleGrant {
  [Required] User User;
  [Required] AppRole Role = AppRole.Member;
  security { allow create when IsAuthenticator; }
}

policy IsAuthenticator => RoleGrant.Any(g => g.User == user && g.Role == AppRole.Authenticator);

[AuthMethod(AuthSlot.Login)]
string SignIn(string email, string password) {
  var u = User.Where(x => x.Email == email).FirstOrDefault();
  if (u == null) { Security.VerifyPassword(password); return ""; }
  if (Security.VerifyPassword(password, u.PasswordHash)) { return Security.IssueJwt(u.Id, u.Email); }
  return "";
}
```

## Signature      {#signature}
```osy syntax
[AuthMethod]                     // callable signed out once a slot names it — the slot is not stated
[AuthMethod(AuthSlot.<Slot>)]    // …and written for <Slot>, one of the slots app.AuthBootstrap has
```

## Description    {#description}

### Which slots are there?   {#slots}
Exactly the method slots of `app.AuthBootstrap` — the argument is a closed set, and a name outside it is refused
with every one of them listed:

| Slot | The step |
|---|---|
| `Login` · `Signup` | sign in · make an account |
| `PasswordResetRequest` · `PasswordReset` · `PasswordChange` | ask for a reset link · use it · change a known password |
| `EmailChange` · `EmailVerifyRequest` · `EmailVerify` · `EmailVerifyCode` · `EmailChangeCancel` | change the address · ask for a proof · prove it by link · by code · call a move off from the old address |
| `SecondFactorSignIn` · `SecondFactorEnable` · `SecondFactorDisable` · `SecondFactorRecoveryCodes` | two-step sign-in |
| `OAuthSignIn` · `OAuthSignup` · `OAuthLink` · `OAuthUnlink` | a provider (Google, GitHub) |
| `AcceptInvite` | join by invitation |
| `PhoneVerify` · `PhoneSignIn` · `SmsSecondStep` | a phone proven by a texted code |
| `EmailDeliveryProblem` | whether mail to an address bounced, before anybody signs in |
| `MachineSignIn` | a program trades a refresh token for a ticket (`POST /api/app-auth/console/machine-token`) |
| `CiSignIn` | a CI job signs in by the OpenID Connect token its CI signed, verified by the platform on an `OidcIssuer` endpoint |
| `PasskeyChallenge` · `PasskeySignIn` · `PasskeyAdd` · `PasskeyRemove` · `PasswordRemove` | passkeys, and turning password sign-in off |

### Why would a package declare it?   {#packages}
A package that ships a whole sign-in flow and states the wiring itself (as `Osysharp.UserAccounts` does) already tells
the compiler where each method goes. A package that ships the methods and leaves the wiring to the app — a shop whose
customers have accounts of the shop's own — could not: when a store left one step unwired, the most the warning
could say was "wire it as one of these twenty-one". Declaring the slot on the method lets it say the line:

```osy syntax
// in the package
[AuthMethod(AuthSlot.EmailVerifyCode)]
public string ConfirmEmailCode(string email, string code) { … }

// the app that wires its bootstrap and forgets that step is told, at its app.AuthBootstrap:
//   … it is written for the `EmailVerifyCode` slot (`[AuthMethod(AuthSlot.EmailVerifyCode)]`) — add
//   `EmailVerifyCode = ConfirmEmailCode` to `app.AuthBootstrap` if this app offers that step.
```

The warning is `AUTHMETHOD_NOT_WIRED`, and it fires only when the step can actually be reached — your code calls the
method, or a package page or component your app shows does. A package page your app takes over without a `[Route]` is
not served, so the steps only it shows say nothing.

### What if it is wired into another slot?   {#mismatch}
Each slot calls its method with that slot's own arguments, so a method written for `EmailVerifyCode` will not work
as `EmailVerify`. Wiring it there is a warning, `AUTHMETHOD_SLOT_MISMATCH`, naming both slots and the line that puts
it right (`Wire it as EmailVerifyCode = ConfirmEmailCode.`). It is a warning rather than an error because the program
still compiles to exactly what you wrote.

## Examples       {#examples}
The app's own methods may declare their slots too — the compiler then holds the wiring to them:

```osy title="two methods, each wired where it says it belongs" test app=security-auth-slot
[AuthMethod(AuthSlot.Signup)]
string MakeAccount(string email, string password) {
  var u = new User { Email = email, PasswordHash = Security.HashPassword(password) };
  new RoleGrant { User = u, Role = AppRole.Member };
  return Security.IssueJwt(u.Id, u.Email);
}

app.AuthBootstrap = new AuthBootstrap { Role = AppRole.Authenticator, Login = SignIn, Signup = MakeAccount };
```

Both are wired where they say they belong, so nothing is said. Swap them — `Login = MakeAccount` — and the compiler
warns that a method written for `Signup` is standing in for a sign-in.

## See also       {#see-also}
- [[AuthMethod] — a function an unauthenticated visitor may call](https://osysharp.com/reference/security/auth-method/) — what `[AuthMethod]` itself means, and the both-ways wiring check
- [auth bootstrap (login, before anyone is signed in)](https://osysharp.com/reference/security/auth-bootstrap/) — the slots, and the principal a wired method runs as
- [The UserAccounts kit — sign-in done properly, once](https://osysharp.com/reference/security/accounts-kit/) — a package that states its own wiring
