Hacker News new | comments | show | ask | jobs | submit login

Caching is affected by the HTTP verbs. For example, GET responses are (sometimes) cacheable because the object may not change. POST responses are not cacheable because they are not contractually required to be idempotent.

Logging is more interesting. I don't necessarily mean printf style logging either. Think about audit trails. For example:

One way to do a password reset is to have:

    /forgot_password/
      GET:
        1) Shows a form asking for your email address.
      POST:
        1) Generates a security token
        2) Sends an email with the token
        3) Shows "Check your inbox!"

    /reset_password/?token=abc123
      GET:
        1) Verifies the security token
        2) Shows a form asking for your new password
      POST:
        1) Re-verifies the security token
        2) Sets the new password
        3) Expires the security token
Now, in this case, you'll notice that the security token needs to be stored somewhere. Where do you put it?

Well, one easy thing to do would be to add a column to the `users` table called `password_reset_token`. But then, of course, you're gonna want to expire a token that's not used in a while, so you need a `password_reset_token_created_at`. And surely you'll want to know which IP address the request came from, in case you start seeing a pattern of abuse. And what if I request my password be reset twice because the first email takes a little long to show up? When the first email finally comes, will the token already be invalid?

An alternate approach would be to restructure the URLs in a CRUD style:

    /password/
      GET:
        Same as GET /forgot_password/
      POST:
        Similar to POST /forgot_password/
        Store the reset request in a `passwords` table

    /password/:token/
      GET:
        Similar to GET /reset_password/
        Supports multiple active tokens
      POST:
        Similar to POST /reset_password/
        Fills the new password into the `passwords` table
This re-imagines passwords as nouns. As a side effect, you get a complete log of whenever anyone changes their password or requests to reset it. Want to enforce password reuse policies? Do analysis of password lifetimes? Track down malicious abuse of your password reset system? Those things are now pretty easy with a schema like this:

    user_id: Integer
    reset_token: String
    hash: String
    salt: String
    created_at: DateTime
    updated_at: DateTime
Here, the reset token is blank if the user is setting their initial password or changing their current password using their old password.

The created_at timestamp is what it sounds like. The updated_at timestamp would match the created_at timestamp, except for when password reset requests are fulfilled, setting the hash and salt.

Checking a user's current password simply involves:

    SELECT hash, salt
    FROM passwords
    WHERE user_id = ?
    AND hash IS NOT NULL
    ORDER BY updated_at DESC
    LIMIT 1
EDIT: I really like this comment :-P I may clean it up and turn it into a submission of its own.



> This re-imagines passwords as nouns. As a side effect, you get a complete log of whenever anyone changes their password or requests to reset it. > Want to enforce password reuse policies? Do analysis of password lifetimes? Track down malicious abuse of your password reset system? > Those things are now pretty easy with a schema like this

I am also proponent of the more "resource oriented" view of an application but I fail to see how the CRUD approach you proposed is unique in order to support the above.. Because, all of the things that you mentioned can be also implemented/supported if you transmit the tokens in query strings. I.e. /password/:token and /reset_password/?token=:token are more or less the same thing from the REST point of view although the first is more user friendly, cache friedly, etc. After all URIs are opaque to the client: http://www.w3.org/DesignIssues/Axioms.html#opaque and that's where HATEOAS enters so the client just needs to know a single (bookmark) URI and the hypermedia will guide to the creation of the rest resource identifiers needed by the application (HATEOAS is indeed the "highest level" of REST: http://martinfowler.com/articles/richardsonMaturityModel.htm...).

Unless you mean that by following the 'noun'-oriented view of the password tokens you can easily spot these operations in the apache logs.. to which I agree if you also include the user id in these URIs...


Whether you use a query string or whatever, isn't super important. In fact, the URLs are completely irrelevant.

The reason I mention URLs at all is because thinking about routes helps you think about resources. Thinking about resources helps you nounify some verbs. This is a good thing because, as I have shown, when dealing with persistence, nouns have advantages over verbs.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: