How would one handle RESTful authentication when authentication is performed with a phone number that must be verified?
For example, let's say a user wants to sign in. The user would hit an endpoint with a phone number that would then queue a text message to be sent to that phone number for verification.
In theory, the two endpoints could look like this:
Finds or creates the user using the phone number, returns that user, and enqueues a text message to be sent to the specified phone number (which is delayed).
Request (application/json)
{
"phone_number": "4151111111"
}
Response 200 (application/json)
{
"id": "85165292-8cce-42a3-960a-ffbc7dac987b",
"name": "James",
"avatar_url": null,
"phone_number": 4151111111
}
The user provides the verification code that was sent in the text message to verify that the user requesting authentication is valid.
Request (application/json)
{
"phone_number_verification_code": "1234"
}
Response 200 (application/json)
{
"id": "85165292-8cce-42a3-960a-ffbc7dac987b",
"name": "James",
"avatar_url": null,
"phone_number": 4151111111,
"auth_token": "ff6828134dd6b2d288qcb8f381b0657c"
}
What is an idiomatic way of going about this verification in a RESTful way? Are the verbs correct? Are the endpoint names correct? Am I missing something?
Some information is missing in the question. Is the resource “user” already created on server and is it just that the phone number is to be verified?
Assuming ‘Yes’. Following scheme looks good to me:-
Authentication
Request
POST /users/<uid>/phones
{
“phone”: “4151111111”
}
Response 201 (Created) should be used when a new resource is added. In this case a new phone number is created so 201 should be returned.
Read the specifications for more information http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
As per REST specifications, a POST method should add a sub-resource. And GET method should list out the sub-resources under the resource represented by URI.
Designing as per these REST specifications, doing a GET on the same URL should probably return a list of phone numbers. This is not mandatory but it should be like this as per REST semantics. So a GET request/response should be like this,
Request
GET /users/<uid>/phones
Response 200 ok
{
“phones”: [
{“phone”: “4151111111”, “verified”: “no”},
{“phone”: “xxxxxxxxxx”, “verified”: “yes”},
…
]
}
For Verifications
Now you already have a resource at server identified by a URI (/users//phones/4151111111). Just that it is not verified. To verify it send a post message to the resource directly. Like this
Request
POST /users/<uid>/phones/4151111111
{
“code”: “1234”
}
Response 200 ok.
Now a GET on "phones" will return "verified": "Yes". Like this,
Request
GET /users/<uid>/phones
Response 200 ok
{
“phones”: [
{“phone”: “4151111111”, “verified”: “yes”},
{“phone”: “xxxxxxxxxx”, “verified”: “yes”},
…
]
}
If "users" are not already created then you can use similar semantics for users also. Like this.
GET /users
POST /users, with payload to add new users. Response 201 (created) etc.
Update
In case the user exist or is a new user, the request could be without "users" in URL like this,
POST /phones
{
“phone”: “4151111111”,
"user": "James"
}
Response could be 201 (Created) but we also have to take care whether the user already existed or not. When the phone number is sent a matching user could be searched in DB and based on different conditions you may return responses like this,
Case 1, user doesn't exist
HTTP/1.1 200 OK
{
"rel": "/phones/4151111111",
"phone": "4151111111",
"verified": "no"
}
Case 2, user exist but phone not verified
HTTP/1.1 200 OK
{
"rel": "/phones/4151111111",
"phone": "4151111111",
"verified": "no"
}
Note that the response is same in case 1 and 2. In case 1, a user is created on server.
Case 3, user exist and phone already verified
HTTP/1.1 200 OK
{
"rel": "/phones/4151111111",
"phone": "4151111111",
"verified": "yes"
}
In case 3 the user already exist and phone is verified; so the client should send a GET request instead of again sending POST with verification code. Client should automatically redirect instead of user initiating a POST.
Case 4, phone already exist but linked to some other user. In this case return with error code or as per your application demands.
Sending URI in response respects the "code on demand" semantics of RESTful style. The client doesn't need to know before hand where to verify.
For verification, now the client will POST the code received in text message to the URI returned in previous response. Like this,
POST /phones/4151111111
{
“code”: “1234”
}
Response could be 201 (created) as the new phone is also added or 200 with desired response body.