Password verification / change using REST API

I want to change the user password using the REST API. This is not a forgotten or password reset function, but a registered user who wants to change his password.

The form requires the current password, a new password, and confirmation for the new password. However, I want to check each form field when the user fills it out. This is trivial for newPassword and confirmNewPassword (client side), but not for currentPassword . The User object is updated using PUT /users/:id . If the password parameter is passed, I check the currentPassword parameter and guarantee that it is correct before saving. However, for verification, I am not sure of the best approach.

I also have POST /users/validate - not sure if this is the best. This checks the user object for both creation and updating, but only for checking the fields belonging to the User object ( email , username , password ). currentPassword not one of them. Think about how to handle this. Some things I reviewed:

POST /users/check_password POST /users/validate (add to validation for currentPassword if this parameter is passed and check that currentPassword matches existing user passwords) and POST /users/:id/validate (a separate check for an existing user requiring currentPassword )

Any thoughts or advice would be greatly appreciated. My first application that provides only REST API functions.

+4
source share
5 answers

To begin with, authentication is often performed outside of the REST model. When a user provides their credentials, they do not provide a REpresentation of their STAT account object (REST); as well as the answer they receive in this way. Since the resource state of a user account does not include both “current” and “new” passwords, providing both a “current” and a “new” password in a request can never truly match the REST model, but professionals often describe the “continuum” of RESTfulness, with some APIs being completely RESTful, while others are RPC (Remote Procedure Call) and REST.

Often there is a RESTful API component that processes data model services, and more often an RPC API component that processes user accounts. You can decide between them. If your project includes superusers who manage multiple user accounts, I would suggest trying a shoehorn in the REST API. If each user only manages his account, I would suggest RPC.

If you decide to use REST for account management, you must select the appropriate HTTP method (GET, POST, DELETE, HEADERS, etc.). Obviously, you need a method that will affect the change on the server (POST, PUT, DELETE, etc.). Unlike the orbfish output above, I'm going to say that PUT would be a suitable method under certain restrictions.

From RFC 2616 , which formally defines our HTTP methods:

“Methods may also have the“ idempotence ”property in that (in addition to errors or expiration errors) the side effects of N> 0 of the same requests are the same as for one request. The GET, HEAD, PUT and DELETE methods share this property. In addition , the OPTIONS and TRACE methods SHOULD NOT have side effects, and therefore are inherently idempotent. "

Idempotency here means that if we make the same request n times in a row, the state of the server under the action of the nth request will be the same as the state of the server under the action of the first request. The orbfish user correctly points out that if we make a request:

 PUT /users/:id/account {current-password: 'a', new-password: 'b'} 

and repeat it:

 PUT /users/:id/account {current-password: 'a', new-password: 'b'} 

for our first request to receive a response indicating success, and our second request should receive a response indicating failure. However, the idempotency of PUT only requires that the server state be the same after both requests. And this: after the first request, the password for user "b", and after the second request, the password for user "b".

I mentioned the above limitations. You might want to block the user after m tries to change the password unsuccessfully; this will provide protection against brute force password attacks. However, this will violate the idempotency of the request: send a valid password request once, and you will change your password, send it again and the server will block you.

By specifying the PUT method, you tell all clients that it is safe to send the request as many times as necessary. If I send a PUT request as a client, and our connection is interrupted so that I do not receive your answer, I know that it is safe to send my PUT again, because it is idempotent: idempotency means that if you receive both requests, it will be the same like on your server, just getting it. But if you are going to block me for an unsuccessful request, then it is unsafe to send a second request until I find out if you received the first.

For this reason, you may consider PATCH or POST. I would suggest using PATCH. While POST is described as adding a new resource to a list or adding data to an existing resource, PATCH is described as a “partial update” of a resource in a known URI. And unlike PUT, PATCH need not be idempotent.

+7
source

I do not like / check _password or / validate because they are verbs; your first "user update" is better than REST.

You can add currentPassword to your user object as an invisible field or as part of an authentication header (username: password).

I would definitely change this from PUT to POST, though, because the same call with the same CurrentPassword cannot execute twice (PUT is idempotent).

+6
source

Another option is to create surrogate resources on user . If you use HATEOAS, you can refer to user/x/pwdchange to the user resource. And I want to clarify pwdchange intended as a noun / resource, not as a verb:

 GET /user/jsmith/pwdchange List of password change requests (history) POST /user/jsmith/pwdchange Create password change request, return id=1 GET /user/jsmith/pwdchange/1 Get password change resource, which would include the outcome (success, failure, etc) 

So, in short, I am creating a resource called "pwdchange" that is fully consistent with the REST representation of the problem domain.

+2
source

You might think why you need to confirm the current password immediately after entering it. I have not seen the site do this. Secondly, great to have a service that just checks something. He is called a practical verse, beating himself, trying to be RESTFul

+1
source

You change the property of the user resource (i.e. password). If you use HTTP Basic for authorization, you already provide the current password, so there is no need to repeat it. I would just PUT the entire user resource with a new password. Example:

 PUT /users/fiddlerpianist HTTP/1.1 Content-Type: application/json Authorization: Basic ZmlkZGxlcnBpYW5pc3Q6bXlub3Rzb2F3ZXNvbWVvbGRwYXNzd29yZA== { "password": "My awesome new password that no one will ever be able to guess!" } 

Another advantage of this is that you do not have to provide the old password if you are a user with authority that has access rights to change the user resource. You may be a customer support specialist who should never ask for the old customer password, but they request a password change by phone (after they have proven their identity to you and you have proven your identity in the system).

You want to avoid using a non-idempotent request in this case (for example, PUT or PATCH), as this can lead to answers whose results are uncertain (suppose the server returns 500 for the non-idepotent request ... you, as a client, do not know what state the server left your resource).

EDITED TO ADD: Please note that there is no “login” concept in a RESTful application. Communication with the client to the server does not have a status (this is a payload and a method that transfers state). In addition, there really is no need to be a validation concept the way you describe it, since a request to change the state of a resource can be met using 200 OK (if it is valid) or 400 Bad Request (if it is not valid).

+1
source

Source: https://habr.com/ru/post/1382544/


All Articles