Hello all, I'm running into an issue on prod where admins can login, but every request made returns a 401
UnauthorizedError: Unauthorized, you must be logged in to make this request.
We can all login. We can all see the item count in each collection, but nothing displays and the requests return a 401.
Does anyone know what's going on? Previously we ran dev and had no issues.
@jmikrut How do I run into every issue ever?
lmao
cries
OK now i can see some of the data
but still get a 401 on every admin request
this must be related to your access control settings
or possibly your CSRF settings?
maybe try and whitelist the domains you are using in the
csrf
property
This was some oddity with access controls that seems to be resolved now.
ahh beautiful
Do you have some more detail on the oddities you noticed here? I seem to be running into a similar issue atm
@Jakey Hmm I'm trying to remember now, I think it was misconfigured access control
Have you changed any of that recently?
I don't think so. the main thing that's changed is I'm attempting to build and serve the application on a remote server. on dev, everything is peachy
@Jakey As jmikrut mentioned, I would try adjusting your CSRF settings
oh sorry, i didn't mention i did that as well
both cors and csrf are setup atm
In addition to the payload csrf settings
In my server.ts file
I also re-specify cors
app.use(
cors({
origin: [
"http://localhost:4200",
"https://www.example.com",
"https://beta.example.com"
],
credentials: true,
})
);
Might be worth trying to add it there as well, just in case payloads isn't being registered
alrighty i'll give it a go
where does the cors method come from @thisisnotchris ?
sorry, its imported
import cors from "cors";
i assume it's just a 'cors' package?
ok cool
@Jakey any luck?
doesn't seem to work
hmm
i guess the cors isn't the issue anyway
it's authorization
a request like:
https://some.link/api/_preferences/localeis returning a 401 unauthorized.
hmmm
Can we check out your payload config?
import { buildConfig } from "payload/config"
import path from "path"
import Users from "./collections/Users"
import Pages from "./collections/Pages"
import Categories from "./collections/Categories"
import Media from "./collections/Media"
import Nav from "./globals/Nav"
export default buildConfig({
serverURL: "https://cms.theqadomain.com",
cors: [
"https://app.theqadomain.com",
],
csrf: [
"https://cms.theqadomain.com",
],
admin: {
user: Users.slug,
webpack: (config) => {
return {
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
fs: path.resolve(__dirname, "mocks/emptyObject.js"),
},
},
}
},
},
collections: [Pages, Categories, Media, Users],
globals: [Nav],
plugins: [],
typescript: {
outputFile: path.resolve(__dirname, "payload-types.ts"),
},
graphQL: {
schemaOutputFile: path.resolve(__dirname, "generated-schema.graphql"),
},
localization: {
locales: ["en", "es", "de"],
defaultLocale: "en",
fallback: true,
},
})
pulled out a plugin property to make it fit
also subbed out the actual domain names
Hmm
Nothing really out of the ordinary here
yeah. hmm
i mean one thing being introduced is nginx to the stack
that doesn't exist locally. so maybe I'm not passing the right headers through or something...
Well
Have you confirmed that your access controls for your collections are in order?
If you think it's unrelated to access control, we can also check out your nginx config
i mean i just gave the Users collection full crud rights. didn't seem to change anything
and if you comment out access control for all collections?
just trying to eliminate any possibilities
the users collection is the only one that has any access overrides atm
OK and Users is also your admins right
uhh... how can i tell?
it's pretty simple atm
import { CollectionConfig } from 'payload/types'
const Users: CollectionConfig = {
slug: 'users',
auth: {
useAPIKey: true
},
admin: {
useAsTitle: 'email',
},
access: {
read: () => true,
create: () => true,
update: () => true,
delete: () => true,
},
fields: [
// Email added by default
// Add more fields as needed
],
}
export default Users
I think you do
admin: {
user: Users.slug,
},
in your payload config
ah ok, right, yes
hmm
i'm using ansible to generate the virtual host for my nginx config. it's also pretty straight forward
server {
listen 443 ssl;
server_name {{ domain }};
# SSL stuff redacted...
location / {
proxy_pass http://localhost:{{ proxy_port }};
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
}
}
nginx for me is this thing where i've just used it for a long time and still don't feel like i know a ton about lol
Not sure if this is helpful
but this is my payload block in nginx
location /payload/ {
proxy_buffering off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
i'll give it a go!
I cant think of what else would cause it, your Payload config looks fine
So I'm guessing it's something with the headers not passing over
what does
proxy_buffering off;
mean btw?
That's if your doing load balancing IIRC
and can be ignored
gotcha, ok!
LMK if that works
hm, i tested and it worked, but i also noticed i was trying out the
*
value for cors
removed your config and left just the
*
and it works. so i guess it's my cors values...
i get a bunch of 401's i don't get on local, but saving certain things works so far
going to bring back my user permissions to the way it was before
Ahhhhh
So you're thinking it was specifically CORS
which is odd, because you whitelisted (for csrf too) your domains
hm, so i returned the User collection to
access: {
read: () => true,
},
and now it's not letting me save anymore despite being the original admin user
i did see that video on access control ... maybe i'll just use Jame's example there to not rely on the dev functionality
well
Add update: () => true as well
I'm not sure if it makes any assumptions if one of the request types are not listed
In our setup I have a Select field on our users
that sets their role
And then i pass a function to my access control
For instance
export const isSuperAdmin: Access<
any, // eslint-disable-line @typescript-eslint/no-explicit-any
Admin
> = ({ req: { user } }) => {
return Boolean(user?.role === "superAdmin");
};
ignore that any
feels shame
lol
i'm still on the typescript expertise road as well, nbd
that seems to be very similar to James' implementation example too
there's also a seeding example... might be better to run that to start the initial user
oh that's sweet, the initial user creation form updates with your collection definition
applied the User permissions shown in this repo
https://github.com/payloadcms/access-control-demo/blob/master/src/collections/Users.ts
it's cool that it gave me roles to work with now. but on deploy, i can't save
on the remote server i mean
that's with the * cors
my brain is kinda fried at this point. need a break lol. I'll get back on this later
Hmm
Let me know when you're back on and we can continue troubleshooting 🙂
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.