Reputation: 2855
I'm using rails-api with devise_token_auth for authentication. I am able to sign in without issue via:
curl -i http://localhost:3000/api/v1/auth/sign_in -F email="[email protected]" -F password="password"
However, sign out fails with a 404 and the error "User was not found or was not logged in." via:
curl -X DELETE -i http://localhost:3000/api/v1/auth/sign_out
I have tried variations of this command with multiple combinations of parameters and header values, such as:
curl -X DELETE -i http://localhost:3000/api/v1/auth/sign_out -F email="[email protected]" -H Access-Token="Ae1yaTYLkSAgdhz3LtPAZg" -H Client="9AmYF6NS8tP6EOD5nPSuxw" -H Expiry="1443073493" -H Uid="[email protected]" -H Token-Type="Bearer"
To no avail. A similarly constructed RSpec test also fails with the same response and error, and the logs indicate the request was processed via DeviseTokenAuth::SessionsController#destroy as JSON.
Of course, I'm not actually using curl for authentication; just verification of the request structure before writing the relevant code.
Upvotes: 4
Views: 3684
Reputation: 2500
In details, do the following steps:
Step 1:
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST http://localhost:3000/api/v1/auth/sign_in -d "{\"email\":\"[email protected]\",\"password\":\"password\"}"
You'll get a response like this:
* Trying ::1...
* Connected to localhost (::1) port 3000 (#0)
> POST /api/v1/auth/sign_in HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.43.0
> Content-Type: application/json
> Accept: application/json
> Content-Length: 50
>
* upload completely sent off: 50 out of 50 bytes
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Access-Token: BqXcWQi0-9faLyxP1LnUKw
< Token-Type: Bearer
< Client: dYSqVgM9VT6fV9Y5MFWpJQ
< Expiry: 1465679853
< Uid: [email protected]
< Content-Type: application/json; charset=utf-8
< Etag: W/"9ad6a23f014a744a7ec83b4e0e9d27aa"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 6566bd38-1ad7-491a-a1ab-e41458b9b704
< X-Runtime: 0.184807
< Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
< Date: Sat, 28 May 2016 21:17:33 GMT
< Content-Length: 135
< Connection: Keep-Alive
<
* Connection #0 to host localhost left intact
{"data":{"id":6,"provider":"email","uid":"[email protected]","name":"testuser","nickname":null,"image":null,"email":"[email protected]"}}%
Step 2:
Now, you want to sign the user out.
curl -i -X DELETE http://localhost:3000/api/v1/auth/sign_out -F access-token="BqXcWQi0-9faLyxP1LnUKw" -F client="dYSqVgM9VT6fV9Y5MFWpJQ" -F uid="[email protected]"
You'll get a response like this:
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Etag: W/"7363e85fe9edee6f053a4b319588c086"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 8f7a297a-6a72-4c9d-a210-48c29fb4bfe0
X-Runtime: 0.095060
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
Date: Sat, 28 May 2016 21:19:18 GMT
Content-Length: 16
Connection: Keep-Alive
{"success":true}%
In step 2, I've added the access-token and client as per the response that we received in step 1 (Access-Token: BqXcWQi0-9faLyxP1LnUKw and Client: dYSqVgM9VT6fV9Y5MFWpJQ).
That's it! :)
I took the help of @user3006381's answer! All credits to him.
Upvotes: 2
Reputation: 2855
Answering my own question, I wasn't returning certain sign_in response header values correctly with the sign_out request.
I found a related post which pointed out some of the critical headers. The trick is to capture the access-token, client, and uid header values from the sign_in response, then include them as parameters in the sign_out request:
curl -i -X DELETE http://localhost:3000/api/v1/auth/sign_out -F access-token="Ae1yaTYLkSAgdhz3LtPAZg" -F client="9AmYF6NS8tP6EOD5nPSuxw" -F uid="[email protected]"
Here's an RSpec test to illustrate and verify:
require 'rails_helper'
RSpec.describe "Authentication", type: :request do
it "logs a user out" do
user = User.create!(
name: "Some Dude",
email: "[email protected]",
password: "password",
confirmed_at: Date.today
)
# initial sign in to generate a token and response
post api_v1_user_session_path, {
email: user.email,
password: user.password
}
expect(user.reload.tokens.count).to eq 1
# sign out request using header values from sign in response
delete destroy_api_v1_user_session_path, {
"access-token": response.header["access-token"],
client: response.header["client"],
uid: response.header["uid"]
}
response_body = JSON.load(response.body)
expect(response_body["errors"]).to be_blank
expect(response.status).to eq 200
# user token should be deleted following sign out
expect(user.reload.tokens.count).to eq 0
end
end
Upvotes: 10