What identifies the user behind a request, for one way of signing in: a password.
Built from two functions, a URL and how long a sign in should last, and nothing else. find turns the key in the session into the application's own user, and credentials turns an email into the key and the stored hash that go with it. Both are the application's, which is what keeps modules/auth off modules/db: the guard never learns that a table exists, and examples/blog supplies two one-line closures over its own read. Constructing one therefore touches nothing, so a boot that never serves opens no connection.
credentials says where the hash is and stops there; comparing it against what was typed is the guard's, in submitted and nowhere else. An application that did its own comparison had to be trusted to answer an unknown email as slowly as a wrong password, which is not a thing a one-line lookup does by accident, and the plain text had to travel out to it to be compared.
The login it carries is unthrottled, and deliberately: every attempt that decodes, right or wrong, known email or not, costs one bcrypt at Password's shipped strength, so a few hundred guesses a second is also a few hundred quarter seconds of this server's CPU a second. A body that will not decode, an empty password or one past the 72 bytes bcrypt reads, never gets that far. Refusing an address after so many tries is the reverse proxy's job, where the addresses and the rest of the application's traffic already are, and not something a guard can do honestly from inside one process.
One guard per user model. required, only and except are how it becomes a Guarded, and every declaration it makes carries carries, the same three route instances, so an application that guards anything has mounted the page it redirects to without writing a line.
Attributes
- Companion
- object
- Source
- Guard.scala
- Graph
-
- Supertypes