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.
Related
I'm trying to setup discord oauth2 pkce using passportjs and the passport-oauth2
const discordStrategy = new OAuth2Strategy({
authorizationURL: 'https://discord.com/api/oauth2/authorize',
tokenURL: 'https://discord.com/api/oauth2/token',
clientID: DISCORD_CLIENT_ID,
clientSecret: DISCORD_CLIENT_SECRET,
callbackURL: DISCORD_CALLBACK_URL,
state: true,
pkce: true,
scope: ['identity', 'scope'],
passReqToCallback: true,
},
(req: Request, accessToken: string, refreshToken: string, profile: DiscordUserProfile, cb: any) => {
prisma.user.findUnique({ where: { email: profile.email ?? '' }}).then(foundUser => {
if (foundUser === null) {
// Create a new user with oauth identity.
} else {
cb(null, foundUser)
}
}).catch(error => {
cb(error, null);
})
});
I've been following the google example as well as some others, these examples indicate that, I should be able to use:
passport.use('discord', discordStrategy);
and
authRouter.get('/discord', passport.authenticate('discord'));
and this should redirect to the OAuth2 providers login page, but instead, I get a 400 Bad Request "The request cannot be fulfilled due to bad syntax." The response body contains an object:
{"scope": ["0"]}
Why is this happening instead of the expected redirect?
My intention is that, once the user logs in, I should get a code, then I can post that code and the code verifier to get an access token, then once the access token is obtained, the actual authenticate call can be made
Edit: I put breakpoints in the passport.authenticate function and I stepped through it. It does actually get through everything and it calls the redirect. The parsed URL it generates, even if I copy it and manually navigate to the URL, it gives me the same, just gives:
{"scope": ["0"]}
and no login page, why?
If you add a version number to the base api url, e.g. /v9 it gives a full error message.
It turned out I had typo'd the scopes, I had 'identity' instead of 'identify' - now this part of the process is working as expected.
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.
In my React Native app -- init app not Expo -- I'm trying to refresh the access_token but my POST call is failing with 401. I'm testing this functionality so I make the POST call some 30 seconds after I login so not sure if this plays a role or not.
In my initial login, I do get a refresh_token along with a valid access_token. I then tell my app to wait 30 seconds and make a POST call that looks like this:
const url = 'https://mydomain.auth0.com/oauth/token';
const postOptions = {
method: 'POST',
url: url,
headers: {
"content-type": 'application/x-www-form-urlencoded'
},
form: {
grant_type: 'refresh_token',
client_id: 'MY_CLIENT_ID',
refresh_token: 'REFRESH_TOKEN_RECEIVED_DURING_LOG_IN'
}
};
fetch(url, postOptions)
.then((response) => {
debugger;
// this is where I get response.status 401
})
Any idea what the issue is here?
Also want to mention that under my application settings, Refresh Token is checked under "Grant Types" but refresh token rotation or expiration are NOT enabled.
I figured this out and sharing it in case others need it in the future.
First, Auth0 documentation is misleading at best. They keep mentioning a regular POST call which doesn't work.
In my React Native app, I use their react-native-auth0 library. This library does offer a refreshToken() method which is what I ended up using.
Before I share the code, here are a couple of really important points:
Be sure to include offline_access in the scope of your initial authentication call for the user. Without including offline_access in your scope, you won't get a refresh_token. Once you receive it along with your access_token and id_token, store it as you'll use it many times. This brings me to the second point.
Unless you set it otherwise, your refresh_token doesn't expire. Therefore, store it some place secure and NOT just in AsyncStorage. As mentioned above, unless, you set it otherwise or it gets revoked, your refresh_token doesn't expire and you use it again and again.
With that said, here's the code. Please keep in mind that at start up, I initialize auth0 as a global variable so that I can access it in different parts of my app.
Here's what my initialization looks like in index.js:
import Auth0 from 'react-native-auth0';
global.auth0 = new Auth0({
domain: "MY_DOMAIN.auth0.com",
clientId: "MY_CLIENT_ID",
});
And here's how I use the refreshToken() method:
// First, retrieve the refresh_token you stored somewhere secure after your initial authentication call for the user
global.auth0.auth.refreshToken({ refreshToken: 'MY_REFRESH_TOKEN' })
.then(result => {
// If you're doing it right, the result will include a new access_token
})
you probably need to add the authorization header with your access_token:
const url = 'https://mydomain.auth0.com/oauth/token';
const postOptions = {
method: 'POST',
url: url,
headers: {
"content-type": 'application/x-www-form-urlencoded',
"Authorization" 'bearer '+access_token,
},
body: JSON.stringify({
grant_type: 'refresh_token',
client_id: 'MY_CLIENT_ID',
refresh_token: 'REFRESH_TOKEN_RECEIVED_DURING_LOG_IN'
});
};
fetch(url, postOptions)
.then((response) => {
debugger;
// this is where I get response.status 401
})
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.
I've got everything working up until Step 2 of the OAuth process where you request the actual token. I'm using a very simple jQuery Post request and constantly getting Access Control Origin errors. I've tried contentType: 'application/json' and everything else I know to try.
It's just not working and I'm not sure the problem. I've confirmed all the variables are set properly before the request. Simple post request...
var url = 'https://[STORENAMEVARIABLE].myshopify.com/admin/oauth/access_token';
var data = JSON.stringify({ client_id: apiKey, client_secret: secret, code: code });
$.ajax({
type: 'POST',
url: url,
data: data,
success: function(data) {
debugger;
},
error: function(data) {
debugger;
}
});
Any ideas what I'm doing wrong?
You need to make your OAuth requests from a server. This is the Javascript cross-domain security kicking in.
If you are using Rails you can use omniAuth and it'll take care of the whole OAuth dance for you. Otherwise you'll have to search around but most popular language have an OAuth library that you can just plug in.