I have a Rails API that serves as the back-end of my application. I use Devise and Doorkeeper. Whenever I try to authenticate a user from React (which is being used as my front-end) it fails.
loginSlice.js
export const loginUser = createAsyncThunk('currentUser/loginUser', async (email, password) => {
const response = await fetch(`${client.BASE_URL}:${client.PORT}${client.USER_AUTH_PATH}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
grant_type: client.grant_type,
email,
password,
client_id: client.client_id,
client_secret: client.client_secret,
}),
});
const data = await response.json();
return data;
});
( I am importing the client, I just wanted to keep the code as minimal as possible in my question )
What I'm getting back is
{
"error": "invalid_grant",
"error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."
}
I am using a grant_type of password (which I'm expecting in the back-end), so that's not the problem. I'm also using the proper client_id and client_secret. Also I'm making the request to the proper path - otherwise I wouldn't recieve the error message from the server, nor would it show the following in my log (see next).
This is what Rails log file is showing me:
Started POST "/oauth/token" for ::1 at 2023-04-14 17:28:02 +0300
Processing by Doorkeeper::TokensController#create as */*
Parameters: {"grant_type"=>"password", "email"=>"[email protected]", "password"=>"[FILTERED]", "client_id"=>"theClientID", "client_secret"=>"[FILTERED]", "token"=>{"grant_type"=>"password", "email"=>"[email protected]", "password"=>"[FILTERED]", "client_id"=>"theClientID", "client_secret"=>"[FILTERED]"}}
[1m[36mDoorkeeper::Application Load (2.1ms)[0m [1m[34mSELECT "oauth_applications".* FROM "oauth_applications" WHERE "oauth_applications"."uid" = $1 LIMIT $2[0m [["uid", "theClientID"], ["LIMIT", 1]]
[1m[36mUser Load (0.9ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["email", "[email protected]"], ["LIMIT", 1]]
↳ app/models/user.rb:18:in `authenticate!'
Completed 400 Bad Request in 619ms (Views: 0.2ms | ActiveRecord: 139.5ms | Allocations: 4627)
However, I created an index.html file and used the exact same function I'm using in my redux thunk and I do get back the authentication token as expected.
index.html
<html>
<head>
<title>Fetcher</title>
</head>
<body>
<script>
async function connectUser() {
fetch('http://localhost:3000/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'password',
email: '[email protected]',
password: 'somePassword',
client_id: 'theClientID',
client_secret: 'theClientSecret'
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))
}
connectUser()
</script>
</body>
</html>
When running this I get the following response:
{
"access_token": "AlXoQgKLPh_sLO6EJfkN5Ld0534zYdG6o4-uOOyuZn0",
"created_at": 1681462632,
"expires_in": 7199,
"refresh_token": "fNAwvF0NUNu_GL27s7jkjUuPXw-Tw_0cdGvi1eL-RjM",
"token_type": "Bearer"
}
And my Rails log shows the following:
Started POST "/oauth/token" for ::1 at 2023-04-14 11:57:07 +0300
Processing by Doorkeeper::TokensController#create as */*
Parameters: {"grant_type"=>"password", "email"=>"[email protected]", "password"=>"[FILTERED]", "client_id"=>"theClientID", "client_secret"=>"[FILTERED]", "token"=>{"grant_type"=>"password", "email"=>"[email protected]", "password"=>"[FILTERED]", "client_id"=>"theClientID", "client_secret"=>"[FILTERED]"}}
[1m[36mDoorkeeper::Application Load (1387.4ms)[0m [1m[34mSELECT "oauth_applications".* FROM "oauth_applications" WHERE "oauth_applications"."uid" = $1 LIMIT $2[0m [["uid", "theClientID"], ["LIMIT", 1]]
[1m[36mUser Load (0.6ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m [["email", "[email protected]"], ["LIMIT", 1]]
↳ app/models/user.rb:18:in `authenticate!'
[1m[36mTRANSACTION (69.8ms)[0m [1m[35mBEGIN[0m
[1m[36mDoorkeeper::AccessToken Exists? (312.1ms)[0m [1m[34mSELECT 1 AS one FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2[0m [["token", "[FILTERED]"], ["LIMIT", 1]]
[1m[36mDoorkeeper::AccessToken Exists? (1.5ms)[0m [1m[34mSELECT 1 AS one FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."refresh_token" = $1 LIMIT $2[0m [["refresh_token", "[FILTERED]"], ["LIMIT", 1]]
[1m[36mDoorkeeper::AccessToken Create (164.9ms)[0m [1m[32mINSERT INTO "oauth_access_tokens" ("resource_owner_id", "application_id", "token", "refresh_token", "expires_in", "scopes", "created_at", "revoked_at", "previous_refresh_token") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"[0m [["resource_owner_id", 1], ["application_id", 1], ["token", "[FILTERED]"], ["refresh_token", "[FILTERED]"], ["expires_in", 7200], ["scopes", ""], ["created_at", "2023-04-14 08:57:12.037562"], ["revoked_at", nil], ["previous_refresh_token", "[FILTERED]"]]
[1m[36mTRANSACTION (69.0ms)[0m [1m[35mCOMMIT[0m
Completed 200 OK in 3637ms (Views: 0.3ms | ActiveRecord: 2005.4ms | Allocations: 7056)
I enabled CORS on the server through rack-cors, I am running the Rails server on port 3000 and the React application on port 3001 (if that makes any difference). I have no more ideas about how this can happen and I would gratefully appreciate help. Thank you!