chore: formatting and linting (#3261)

* chore: lint packages/payload

* chore: lint packages/db-postgres

* chore: lint packages/db-mongodb

* chore: update eslintrc exclusion rules

* chore: update eslintrc exclusion rules

* chore: lint misc files

* chore: run prettier through packages

* chore: run eslint on payload again

* chore: prettier misc files

* chore: prettier docs
This commit is contained in:
Alessio Gravili
2023-09-01 17:39:44 +02:00
committed by GitHub
parent 5f7673d735
commit ae7d6f97d2
1403 changed files with 48072 additions and 46231 deletions

View File

@@ -41,8 +41,8 @@ Technically, both of these options will work for third-party integrations but th
To enable API keys on a collection, set the `useAPIKey` auth option to `true`. From there, a new interface will appear in the Admin panel for each document within the collection that allows you to generate an API key for each user in the Collection.
<Banner type="success">
User API keys are encrypted within the database, meaning that if your database
is compromised, your API keys will not be.
User API keys are encrypted within the database, meaning that if your database is compromised,
your API keys will not be.
</Banner>
#### Authenticating via API Key
@@ -52,31 +52,31 @@ To authenticate REST or GraphQL API requests using an API key, set the `Authoriz
**For example, using Fetch:**
```ts
import User from '../collections/User';
import User from '../collections/User'
const response = await fetch("http://localhost:3000/api/pages", {
const response = await fetch('http://localhost:3000/api/pages', {
headers: {
Authorization: `${User.slug} API-Key ${YOUR_API_KEY}`,
},
});
})
```
Payload ensures that the same, uniform access control is used across all authentication strategies. This enables you to utilize your existing access control configurations with both API keys and the standard email/password authentication. This consistency can aid in maintaining granular control over your API keys.
#### API Key *Only* Authentication
#### API Key _Only_ Authentication
If you want to use API keys as the only authentication method for a collection, you can disable the default local strategy by setting `disableLocalStrategy` to `true` on the collection's `auth` property. This will disable the ability to authenticate with email and password, and will only allow for authentication via API key.
```ts
import { CollectionConfig } from 'payload/types';
import { CollectionConfig } from 'payload/types'
export const Customers: CollectionConfig = {
slug: 'customers',
auth: {
useAPIKey: true,
disableLocalStrategy: true,
}
};
},
}
```
### Forgot Password
@@ -90,17 +90,16 @@ Function that accepts one argument, containing `{ req, token, user }`, that allo
<Banner type="success">
<strong>Tip:</strong>
<br />
HTML templating can be used to create custom email templates, inline CSS
automatically, and more. You can make a reusable function that standardizes
all email sent from Payload, which makes sending custom emails more DRY.
Payload doesn't ship with an HTML templating engine, so you are free to choose
your own.
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are
free to choose your own.
</Banner>
Example:
```ts
import { CollectionConfig } from 'payload/types';
import { CollectionConfig } from 'payload/types'
export const Customers: CollectionConfig = {
slug: 'customers',
@@ -109,7 +108,7 @@ export const Customers: CollectionConfig = {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to reset their password
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`;
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`
return `
<!doctype html>
@@ -123,22 +122,21 @@ export const Customers: CollectionConfig = {
</p>
</body>
</html>
`;
}
`
},
// highlight-end
}
}
};
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for resetting their
password, such as a page on the frontend of your app or similar, you need to
handle making the call to the Payload REST or GraphQL reset-password operation
yourself on your frontend, using the token that was provided for you. Above,
it was passed via query parameter.
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
you. Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
@@ -173,8 +171,7 @@ Function that accepts one argument, containing `{ req, token, user }`, that allo
Example:
```ts
import { CollectionConfig } from 'payload/types';
import { CollectionConfig } from 'payload/types'
export const Customers: CollectionConfig = {
slug: 'customers',
@@ -183,24 +180,23 @@ export const Customers: CollectionConfig = {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to verify their account
const url = `https://yourfrontend.com/verify?token=${token}`;
const url = `https://yourfrontend.com/verify?token=${token}`
return `Hey ${user.email}, verify your email by clicking here: ${url}`;
}
return `Hey ${user.email}, verify your email by clicking here: ${url}`
},
// highlight-end
}
}
};
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for email verification,
such as a page on the frontend of your app or similar, you need to handle
making the call to the Payload REST or GraphQL verification operation yourself
on your frontend, using the token that was provided for you. Above, it was
passed via query parameter.
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
@@ -231,9 +227,8 @@ As of Payload `1.0.0`, you can add additional authentication strategies to Paylo
Behind the scenes, Payload uses PassportJS to power its local authentication strategy, so most strategies listed on the PassportJS website will work seamlessly. Combined with adding custom components to the admin panel's `Login` view, you can create advanced authentication strategies directly within Payload.
<Banner type="warning">
This is an advanced feature, so only attempt this if you are an experienced
developer. Otherwise, just let Payload's built-in authentication handle user
auth for you.
This is an advanced feature, so only attempt this if you are an experienced developer. Otherwise,
just let Payload's built-in authentication handle user auth for you.
</Banner>
The `strategies` property is an array that takes objects with the following properties:
@@ -250,7 +245,6 @@ However, if you pass a function to `strategy`, `name` is a required property.
In either case, Payload will prefix the strategy name with the collection `slug` that the strategy is passed to.
### Admin autologin
For testing and demo purposes you may want to skip forcing the admin user to login in order to access the panel.
@@ -259,29 +253,33 @@ The default is that all users will have to login and this should not be enabled
#### autoLogin Options
| Option | Description |
| -------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
The recommended way to use this feature is behind an environment variable to ensure it is disabled when in production.
**Example:**
```ts
export default buildConfig({
admin: {
user: 'users',
// highlight-start
autoLogin: process.env.PAYLOAD_PUBLIC_ENABLE_AUTOLOGIN === 'true' ? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
} : false,
autoLogin:
process.env.PAYLOAD_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
},
collections: [ /** */],
collections: [
/** */
],
})
```

View File

@@ -17,6 +17,7 @@ The Access operation returns what a logged in user can and can't do with the col
`GET http://localhost:3000/api/access`
Example response:
```ts
{
canAccessAdmin: true,
@@ -77,6 +78,7 @@ Returns either a logged in user with token or null when there is no logged in us
`GET http://localhost:3000/api/[collection-slug]/me`
Example response:
```ts
{
user: { // The JWT "payload" ;) from the logged in user
@@ -108,6 +110,7 @@ query {
Accepts an `email` and `password`. On success, it will return the logged in user as well as a token that can be used to authenticate. In the GraphQL and REST APIs, this operation also automatically sets an HTTP-only cookie including the user's token. If you pass an Express `res` to the Local API operation, Payload will set a cookie there as well.
**Example REST API login**:
```ts
const res = await fetch('http://localhost:3000/api/[collection-slug]/login', {
method: 'POST',
@@ -117,10 +120,10 @@ const res = await fetch('http://localhost:3000/api/[collection-slug]/login', {
body: JSON.stringify({
email: 'dev@payloadcms.com',
password: 'this-is-not-our-password...or-is-it?',
})
}),
})
const json = await res.json();
const json = await res.json()
// JSON will be equal to the following:
/*
@@ -168,6 +171,7 @@ const result = await payload.login({
As Payload sets HTTP-only cookies, logging out cannot be done by just removing a cookie in JavaScript, as HTTP-only cookies are inaccessible by JS within the browser. So, Payload exposes a `logout` operation to delete the token in a safe way.
**Example REST API logout**:
```ts
const res = await fetch('http://localhost:3000/api/[collection-slug]/logout', {
method: 'POST',
@@ -194,6 +198,7 @@ This operation requires a non-expired token to send back a new one. If the user'
If successful, this operation will automatically renew the user's HTTP-only cookie and will send back the updated token in JSON.
**Example REST API token refresh**:
```ts
const res = await fetch('http://localhost:3000/api/[collection-slug]/refresh-token', {
method: 'POST',
@@ -202,7 +207,7 @@ const res = await fetch('http://localhost:3000/api/[collection-slug]/refresh-tok
},
})
const json = await res.json();
const json = await res.json()
// JSON will be equal to the following:
/*
@@ -233,7 +238,10 @@ mutation {
```
<Banner type="success">
The Refresh operation will automatically find the user's token in either a JWT header or the HTTP-only cookie. But, you can specify the token you're looking to refresh by providing the REST API with a `token` within the JSON body of the request, or by providing the GraphQL resolver a `token` arg.
The Refresh operation will automatically find the user's token in either a JWT header or the
HTTP-only cookie. But, you can specify the token you're looking to refresh by providing the REST
API with a `token` within the JSON body of the request, or by providing the GraphQL resolver a
`token` arg.
</Banner>
### Verify by Email
@@ -241,13 +249,14 @@ mutation {
If your collection supports email verification, the Verify operation will be exposed which accepts a verification token and sets the user's `_verified` property to `true`, thereby allowing the user to authenticate with the Payload API.
**Example REST API user verification**:
```ts
const res = await fetch(`http://localhost:3000/api/[collection-slug]/verify/${TOKEN_HERE}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
})
```
**Example GraphQL Mutation**:
@@ -274,6 +283,7 @@ If a user locks themselves out and you wish to deliberately unlock them, you can
To restrict who is allowed to unlock users, you can utilize the [`unlock`](/docs/access-control/overview#unlock) access control function.
**Example REST API unlock**:
```ts
const res = await fetch(`http://localhost:3000/api/[collection-slug]/unlock`, {
method: 'POST',
@@ -308,6 +318,7 @@ The link to reset the user's password contains a token which is what allows the
By default, the Forgot Password operations send users to the Payload Admin panel to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/config#forgot-password).
**Example REST API Forgot Password**:
```ts
const res = await fetch(`http://localhost:3000/api/[collection-slug]/forgot-password`, {
method: 'POST',
@@ -317,7 +328,7 @@ const res = await fetch(`http://localhost:3000/api/[collection-slug]/forgot-pass
body: JSON.stringify({
email: 'dev@payloadcms.com',
}),
});
})
```
**Example GraphQL Mutation**:
@@ -336,13 +347,18 @@ const token = await payload.forgotPassword({
data: {
email: 'dev@payloadcms.com',
},
disableEmail: false // you can disable the auto-generation of email via local API
});
disableEmail: false, // you can disable the auto-generation of email via local API
})
```
<Banner type="success">
<strong>Tip:</strong><br/>
You can stop the reset-password email from being sent via using the local API. This is helpful if you need to create user accounts programmatically, but not set their password for them. This effectively generates a reset password token which you can then use to send to a page you create, allowing a user to "complete" their account by setting their password. In the background, you'd use the token to "reset" their password.
<strong>Tip:</strong>
<br />
You can stop the reset-password email from being sent via using the local API. This is helpful if
you need to create user accounts programmatically, but not set their password for them. This
effectively generates a reset password token which you can then use to send to a page you create,
allowing a user to "complete" their account by setting their password. In the background, you'd
use the token to "reset" their password.
</Banner>
### Reset Password
@@ -350,6 +366,7 @@ const token = await payload.forgotPassword({
After a user has "forgotten" their password and a token is generated, that token can be used to send to the reset password operation along with a new password which will allow the user to reset their password securely.
**Example REST API Reset Password**:
```ts
const res = await fetch(`http://localhost:3000/api/[collection-slug]/reset-password`, {
method: 'POST',

View File

@@ -12,13 +12,14 @@ keywords: authentication, config, configuration, overview, documentation, Conten
/>
<Banner>
Payload provides for highly secure and customizable user Authentication out of the box, which allows for users to identify themselves to Payload.
Payload provides for highly secure and customizable user Authentication out of the box, which
allows for users to identify themselves to Payload.
</Banner>
Authentication is used within the Payload Admin panel itself as well as throughout your app(s) themselves however you determine necessary.
![Authentication admin panel functionality](https://payloadcms.com/images/docs/auth-admin.jpg)
*Admin panel screenshot depicting an Admins Collection with Auth enabled*
_Admin panel screenshot depicting an Admins Collection with Auth enabled_
**Here are some common use cases of Authentication outside of Payload's dashboard itself:**
@@ -38,7 +39,7 @@ Every Payload Collection can opt-in to supporting Authentication by specifying t
Simple example collection:
```ts
import { CollectionConfig } from 'payload/types';
import { CollectionConfig } from 'payload/types'
export const Admins: CollectionConfig = {
slug: 'admins',
@@ -56,13 +57,8 @@ export const Admins: CollectionConfig = {
name: 'role',
type: 'select',
required: true,
options: [
'user',
'admin',
'editor',
'developer',
],
}
options: ['user', 'admin', 'editor', 'developer'],
},
],
}
```
@@ -86,8 +82,11 @@ Successfully logging in returns a `JWT` (JSON web token) which is how a user wil
You can specify what data gets encoded to the JWT token by setting `saveToJWT` to true in your auth collection fields. If you wish to use a different key other than the field `name`, you can provide it to `saveToJWT` as a string. It is also possible to use `saveToJWT` on fields that are nested in inside groups and tabs. If a group has a `saveToJWT` set it will include the object with all sub-fields in the token. You can set `saveToJWT: false` for any fields you wish to omit. If a field inside a group has `saveToJWT` set, but the group does not, the field will be included at the top level of the token.
<Banner type="success">
<strong>Tip:</strong><br/>
You can access the logged-in user from access control functions and hooks via the Express <strong>req</strong>. The logged-in user is automatically added as the <strong>user</strong> property.
<strong>Tip:</strong>
<br />
You can access the logged-in user from access control functions and hooks via the Express{' '}
<strong>req</strong>. The logged-in user is automatically added as the <strong>user</strong>{' '}
property.
</Banner>
### HTTP-only cookies
@@ -107,16 +106,19 @@ Fetch example, including credentials:
```ts
const response = await fetch('http://localhost:3000/api/pages', {
credentials: 'include',
});
})
const pages = await response.json();
const pages = await response.json()
```
For more about how to automatically include cookies in requests from your app to your Payload API, [click here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Sending_a_request_with_credentials_included).
<Banner type="success">
<strong>Tip:</strong><br/>
To make sure you have a Payload cookie set properly in your browser after logging in, you can use Chrome's Developer Tools - Application - Cookies - [your-domain-here]. The Chrome Developer tools will still show HTTP-only cookies, even when JavaScript running on the page can't.
<strong>Tip:</strong>
<br />
To make sure you have a Payload cookie set properly in your browser after logging in, you can use
Chrome's Developer Tools - Application - Cookies - [your-domain-here]. The Chrome Developer tools
will still show HTTP-only cookies, even when JavaScript running on the page can't.
</Banner>
### CSRF Protection
@@ -128,28 +130,33 @@ For example, let's say you have a very popular app running at coolsite.com. This
So, if a user of coolsite.com is logged in and just browsing around on the internet, they might stumble onto a page with bad intentions. That bad page might automatically make requests to all sorts of sites to see if they can find one that they can log into - and coolsite.com might be on their list. If your user was logged in while they visited that evil site, the attacker could do whatever they wanted as if they were your coolsite.com user by just sending requests to the coolsite API (which would automatically include the auth cookie). They could send themselves a bunch of money from your user's account, change the user's password, etc. This is what a CSRF attack is.
<Banner type="warning">
<strong>To protect against CSRF attacks, Payload only accepts cookie-based authentication from domains that you explicitly whitelist.</strong>
<strong>
To protect against CSRF attacks, Payload only accepts cookie-based authentication from domains
that you explicitly whitelist.
</strong>
</Banner>
To define domains that should allow users to identify themselves via the Payload HTTP-only cookie, use the `csrf` option on the base Payload config to whitelist domains that you trust.
`payload.config.ts`:
```ts
import { buildConfig } from 'payload/config';
import { buildConfig } from 'payload/config'
const config = buildConfig({
collections: [
// collections here
],
// highlight-start
csrf: [ // whitelist of domains to allow cookie auth from
csrf: [
// whitelist of domains to allow cookie auth from
'https://your-frontend-app.com',
'https://your-other-frontend-app.com',
],
// highlight-end
});
})
export default config;
export default config
```
### Identifying users via the Authorization Header
@@ -157,11 +164,12 @@ export default config;
In addition to authenticating via an HTTP-only cookie, you can also identify users via the `Authorization` header on an HTTP request.
Example:
```ts
const request = await fetch('http://localhost:3000', {
headers: {
Authorization: `JWT ${token}`
}
Authorization: `JWT ${token}`,
},
})
```

View File

@@ -11,48 +11,47 @@ Because Payload uses your existing Express server, you are free to add whatever
This approach has a ton of benefits - it's great for isolation of concerns and limiting scope, but it also means that your additional routes won't have access to Payload's user authentication.
<Banner type="success">
You can make full use of Payload's built-in authentication within your own
custom Express endpoints by adding Payload's authentication middleware.
You can make full use of Payload's built-in authentication within your own custom Express
endpoints by adding Payload's authentication middleware.
</Banner>
<Banner type="warning">
Payload must be initialized before the `payload.authenticate` middleware can
be used. This is done by calling `payload.init()` prior to adding the
middleware.
Payload must be initialized before the `payload.authenticate` middleware can be used. This is done
by calling `payload.init()` prior to adding the middleware.
</Banner>
Example in `server.js`:
```ts
import express from "express";
import payload from "payload";
import express from 'express'
import payload from 'payload'
const app = express();
const app = express()
const start = async () => {
await payload.init({
secret: "PAYLOAD_SECRET_KEY",
mongoURL: "mongodb://localhost/payload",
secret: 'PAYLOAD_SECRET_KEY',
mongoURL: 'mongodb://localhost/payload',
express: app,
});
})
const router = express.Router();
const router = express.Router()
// Note: Payload must be initialized before the `payload.authenticate` middleware can be used
router.use(payload.authenticate); // highlight-line
router.use(payload.authenticate) // highlight-line
router.get("/", (req, res) => {
router.get('/', (req, res) => {
if (req.user) {
return res.send(`Authenticated successfully as ${req.user.email}.`);
return res.send(`Authenticated successfully as ${req.user.email}.`)
}
return res.send("Not authenticated");
});
return res.send('Not authenticated')
})
app.use("/some-route-here", router);
app.use('/some-route-here', router)
app.listen(3000);
};
app.listen(3000)
}
start();
start()
```