KeystoneJS Signup via Rest request - keystonejs

Using sydjs as book to get everything working
I'm trying to signup users via POST request via api:
/api/app/signup-email
Whenever I send data with only email&pass - everything works. If I try to add name parameter - it always fails.
Registration on front-end works as it should
Sending data as:
let parameters = [
"email": "\(email)",
"password": "\(password)",
"name": [
"first": "\(firstname)",
"last": "\(lastname)"
]
]
Maybe anyone has any idea why it doesn't work with name included? Thx.

It won't work because login request in Keystone need a _CSRF token validation, you need to provide it as parameter.
One example is first make a GET request to your login page (The CSRF Token will be in the HEADER response), save it and then make your login request passing the CSRF token obtained in the previous request.
This will be helpful KeystoneJS signin

I implemented a login against the REST-API of keystone (v4.0.0-beta.5). On the client-side I chose npm request. I enabled request's cookie-functionality (config option request.defaults({ jar: true });).
The login consisted of two separate-requests:
A simple GET-request against: https://www.yourkeystoneapp.com/keystone/session/signin
npm request will receive a cookie containing the CSRF token. There is nothing else you need to do with it. npm request will use the received cookie for all subsequent http-requests.
A POST-request containing a simple JSON body with your credentials:
{
email: 'user#yourkeystoneapp.com',
password: 'yourpassword'
}
The POST-request will be answered by Keystone with a valid user-object, if the credentials were correct.
All subsequent http-requests will be part of a valid session, as long as the CSRF-token is valid.
Code examples:
// enable cookies
request.defaults({
jar: true
});
// first request to obtain the cookie
request('https://www.yourkeystoneapp.com/signin', {/* some options */});
// second request to POST your credentials
var loginOptions = {
method: 'POST',
url: 'https://www.yourkeystoneapp.come/api/session/signin',
headers: {
'content-type': 'application/json',
'accept': 'application/json'
},
body: JSON.stringify({
email: 'user#yourkeystoneapp.com',
password: 'yourpassword
})
};
// issue POST request.
request(loginOptions);
// You are now logged in
If you are using npm request, as I did, you have to take a couple of measures to sync the requests you issue, as npm request works asynchronously. Making use of npm request's API and its callback-functions is mandatory.

Related

Sync Token in Postman

A fresher to postman, currently working on API project where I need to delivery to the API and Token the client to integrate with them system, good is I successfully configure the Authorization as OAuth Type as Password Credentials and receiving perfect response as 200.
The issue/confusion is Token is getting expire every hour, I need to Get new Access Token every time.
So, the question is, is it anyway I can overcome this issue?
that no need to get new/refresh token.
can provide the one fix token to client.
You can do it like here. You can get the token in the pre-request field of the collection or request.
https://stackoverflow.com/a/73911458/10126763
EDIT
We can adapt it like this:
Take this and paste it in the "pre-request" field of the collection or the request you will use directly. Create an "environment" value named "accessToken". When each request is run, this method will run first and send the token value to the value in the environment.
// Set refresh and access tokens
const loginRequest = {
url: "exampleurl.com/etc/etc", //YOUR URL
method: 'GET',
header: {
'content-type': 'application/json',
'Accept': "*/*"
} //Since you will be using GET, I deleted the body. If you are sending value you can get the body field from the other example in the link.
};
pm.sendRequest(loginRequest, function (err, res) {
pm.environment.set("accessToken", res.json().accessToken); //The token returned in the response and the environment value to which the value will be sent
});

Strapi doesn't authorize JWT

Good morning,
I've encountered a weird issue with my strapi-project.
I have a standard user model which I query for info on the user's profile page via the /users/me endpoint. This was all working fine last week but as I tried logging in this morning, the authorization appeared to not work anymore. I log my user in via this code:
....
async submitForm() {
axios.post('http://localhost:1337/auth/local', {
'identifier': this.email,
'password': this.password
})
.then((response) => {
const { jwt, user } = response.data;
window.localStorage.setItem('jwt', jwt);
window.localStorage.setItem('userData', JSON.stringify(user));
router.push('/dashboard');
})
.catch((e) => {
this.$store.commit('LOGIN_ERROR', e)
});
},
...
Which then redirects to my dashboard which queries the /users/me endpoint like so:
let token = localStorage.jwt;
axios.get(`http://localhost:1337/users/me`, {
headers: {
Authorization: `Bearer ${token}`
}
})
.then((response) => {
console.log(response.data);
})
A few days ago this was working fine, also the token variable used in the post contais the token returned from the backend after logging in. Now strapi gives me an error in the console:
[2021-10-16T07:16:52.568Z] debug GET /users/me (5 ms) 500
[2021-10-16T07:17:03.231Z] debug POST /auth/local (76 ms) 200
[2021-10-16T07:17:24.915Z] error TypeError: Cannot read property 'type' of null
at module.exports (/home/user/WebstormProjects/strapi-project/node_modules/strapi-plugin-users-permissions/config/policies/permissions.js:35:14)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi-utils/lib/policy.js:68:5
at async serve (/home/user/WebstormProjects/strapi-project/node_modules/koa-static/index.js:59:5)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/parser/index.js:48:23
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/xss/index.js:26:9
My first guess was that maybe something with axios was wrong e.g. that the token wasn't sent correctly in the request so I tried the same thing with webstorm's http client:
POST http://localhost:1337/auth/local
Content-Type: application/json
{
"identifier": "test#test.com",
"password": "..."
}
Which returns the user and token:
"jwt": "<TOKEN>",
If I try using this token to authenticate the user, however a get a 401
GET http://localhost:1337/users/me
Authorization: "Bearer <token>"
Accept: application/json
returns
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid token."
}
So I tried figuring out what was going on there and after an hour I noticed that when looking at the user in the backend the user didn't have the authenticated role assigned. When I changed this manually in the backend, the request authorization works again.
So can anyone maybe tell me what is going on here? Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated, which was working some days back.
Is there something I'm missing?
Any help would be greatly appreciated,
greetings, derelektrischemoench
Okay, so let me reply to your first part:
"Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated"
Answer is, not really. When you send valid credentials to the auth/local, Strapi just checks the database for matching username/email and password. If a user is found, then it fetches the role assigned that user and puts all the data in ctx.state.user.role. So you could have many other roles, like Viewer, Commenter etc with each having different set of access limits.
The different roles can be created here:
http://localhost:1337/admin/settings/users-permissions/roles
So depending on the roles assigned, Strapi will just fetch and store the values in ctx.state.user.role on each request via the strapi-plugin-users-permissions plugin for your convenience, so that you can easily check which user it is and which role it has in any controller or service file using the ctx from the request to provide any additional functionality.
You can check how it does it in the following file:
node_modules/strapi-plugin-users-permissions/config/policies/permissions.js
Now coming to what could have caused it:
Well it could have been you yourself. Possibly while saving the user or viewing user details you could have removed the role from the user and saved the record.
The other possibility could be a database switch.
It can also be a Strapi version upgrade that caused, but it's highly unlikely.
You could have a update query in the your code that updates the user model, where you might have missed the role parameter. So check your code once.
Nevertheless, it can simply be solved by re-assigning the user roles via the users module.

Setting a JWT token in header from localStorage for redirect

I am using JWT tokens to authenticate users and protect certain routes.
My app is set up with a login function that receives a username and password from the front end, authenticates the user and passes back a token.
I am able to store my token in localStorage like this.
localStorage.setItem("Token", token);
Any ajax call going forward should be able to use
$.ajax({
type: 'GET',
url: '/protected_route,
headers: {
"Accept": "application/json",
"Token" : localStorage.getItem(Token),
success: (data) => {
// do something with the data
}}
This should work as long as the token is still set in localStorage and not expired. My question is, if I want to redirect right after login to a protected path, how would I do that?
window.location = '/my_profile
does not let me set headers.
I am surprised that I could not find anything regarding this issue. Seems like very common use case when using JWT.
Thanks!!

Nuxt SSR - i can't check if a user is authenticated

I'm trying to work on a Nuxt SSR frontend that uses a Django backend with Session Authentication.
I would like to have some SSR pages as well as client rendered pages in my frontend, so i'm using Universal mode.
The problem is that i did not find a working approach to check if a user is authenticated before loading a page, so i can't restrict pages to anonymous users. In order to check if a user is authenticated, Django will check if the request's headers contain a cookie, and according to that return if the user is authenticated or not.
Here is what i tried:
1) Middleware
export default async function ({context, redirect}) {
axios.defaults.withCredentials = true;
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//Redirect if user is authenticated
}).catch(function (error) {
console.log(error)
});
}
Here i'm sending a request to my backend to check if the user is authenticated. The problem is that the middleware is executed from server side, which means there will never be any cookie in the request, even if the user is authenticated. This means that every time i refresh the page, according to the middleware the user is always anonymous, even when the user is authenticated.
2) Plugin
export default function (context, inject) {
if (process.client){
console.log('client')
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//IF AUTHENTICATED, REDIRECT
context.redirect('/')
}).catch(function (error) {
console.log(error)
});
} else {
console.log('server')
}
}
Here i'm trying the same but with a plugin, and i'm "forcing" the plugin to check if the user is authenticated on the backend only when the plugin executes from client side. This works, cookies are sent in the headers and Django receives the cookie, but the problem with this solution is that Nuxt doesn't allow redirecting to other pages from a plugin (https://github.com/nuxt/nuxt.js/issues/4491).
3) Using beforeMount() in Vue
I tried to do that using beforeMount() from my Vue pages, but the problem is that since it will execute AFTER idration, the page will be loaded and after 1/2 seconds the redirect happens, which is kind of ugly.
Is it possible that there isn't a way to do this? Any kind of advice is appreciated
EDIT: the problem is not that i don't know how to code this, the problem is that when Nuxt sends a request to my backend from the server side middleware, the request will not contain any cookie, and because of this my Django backend cannot check the session cookie, which means that the backend cannot check whether or not the user is authenticated. The same code works when the middleware is executed from client side (if i navigate directly to the page instead of refreshing), because the request will contain the cookies.
I'm trying to understand if this is normal or not, but this could be an issue with Nuxt.
I know this a year old question and it was probably about nuxt 2, now nuxt 3 is out and running and I found my self with the same problem and here is how I solved it, just in case someone stumble here just like I did.
With Nuxt 3 server side you can use useFetch with the options headers: useRequestHeaders(['cookie'])
const { data, error, pending, refresh } = await useFetch(api.auth,
{
credentials: "include",
headers: useRequestHeaders(['cookie'])
}
);
There are a few issues you need to be aware of:
_ The cache, if you perform the same request with the same parameters it will return the same cached response (it won't even call the end point API). Try to use the key option with different values or the returned refresh method and check the doc "Data fetching" for more info.
_ The cookies, any cookie generate server side won't be shared with the client side, this means if the API generate a new token or session cookie on server side the browser won't receive those cookies and may generate new ones, this may get you in some 400 - bad request if you use session with CSRF, check this issue for more info.
I do have a working middleware with this
export default ({ redirect, store }) => {
if (store?.$auth?.$state?.loggedIn) {
redirect('https://secure.url')
} else {
redirect('https://login.please')
}
})

oAuth returning 400 bad request

I am making a request to my auth server using the example from cypress documentation below.
https://github.com/cypress-io/cypress-example-recipes/blob/aa434ffc29946d545daf4c94019f9692eb0db3e0/examples/logging-in__single-sign-on/cypress/integration/logging-in-single-sign-on-spec.js#L47
Following is my configuration but I am getting a 400 bad request. The url should take me to the login form and authorise the user and then redirect to call back page to get the token.
Am i missing something?
const options = {
method: 'POST',
url: 'https://fakeauthserver.net/Account/Login',
qs: {
redirect_uri: 'http://localhost:9000/login/callback',
client_id: 'webapp',
response_type: 'code',
scope: 'full-access'
},
form: true,
body: {
Username: 'fakeusername#grr.la',
Password: '123456',
button: 'login'
}
};
_.extend(config);
cy.request(config)
Usually, the 400 Bad Request error occurs when you have made an error in the parameters sent in the request. Check whether you have sent all the parameters and whether they are the same as the ones registered in your identity provider.
Also, it might be due to POST request you have made here. According to the OAuth specification, authorization request should be a GET request.