From c1eb9d1727daf96375e73943882621127b78e593 Mon Sep 17 00:00:00 2001 From: Travis Mcgeehan Date: Tue, 28 Nov 2023 16:23:18 -0500 Subject: [PATCH] feat: support OAuth 2.0 format Authorization: Bearer tokens in headers --- docs/authentication/overview.mdx | 2 +- packages/payload/src/auth/getExtractJWT.ts | 36 +++++++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/docs/authentication/overview.mdx b/docs/authentication/overview.mdx index 4ad0a6680..0732a036d 100644 --- a/docs/authentication/overview.mdx +++ b/docs/authentication/overview.mdx @@ -82,7 +82,7 @@ Once enabled, each document that is created within the Collection can be thought ### Token-based auth -Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization` header, Payload will automatically identify the user and add its user JWT data to the Express `req`, which is available throughout Payload including within access control, hooks, and more. +Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization: JWT` or `Authorization: Bearer` header, Payload will automatically identify the user and add its user JWT data to the Express `req`, which is available throughout Payload including within access control, hooks, and more. 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. diff --git a/packages/payload/src/auth/getExtractJWT.ts b/packages/payload/src/auth/getExtractJWT.ts index 2ecf9dc4b..f37a54f31 100644 --- a/packages/payload/src/auth/getExtractJWT.ts +++ b/packages/payload/src/auth/getExtractJWT.ts @@ -1,4 +1,3 @@ -/* eslint-disable react/destructuring-assignment */ import type { Request } from 'express' import type { SanitizedConfig } from '../config/types' @@ -8,22 +7,31 @@ import parseCookies from '../utilities/parseCookies' const getExtractJWT = (config: SanitizedConfig) => (req: Request): null | string => { - if (req && req.get) { - const jwtFromHeader = req.get('Authorization') - const origin = req.get('Origin') + if (!req?.get) { + return null + } - if (jwtFromHeader && jwtFromHeader.indexOf('JWT ') === 0) { - return jwtFromHeader.replace('JWT ', '') - } + const jwtFromHeader = req.get('Authorization') + const origin = req.get('Origin') - const cookies = parseCookies(req) - const tokenCookieName = `${config.cookiePrefix}-token` + if (jwtFromHeader?.indexOf('JWT ') === 0) { + return jwtFromHeader.replace('JWT ', '') + } + // allow RFC6750 OAuth 2.0 compliant Bearer tokens + // in addition to the payload default JWT format + if (jwtFromHeader?.indexOf('Bearer ') === 0) { + return jwtFromHeader.replace('Bearer ', '') + } - if (cookies && cookies[tokenCookieName]) { - if (!origin || config.csrf.length === 0 || config.csrf.indexOf(origin) > -1) { - return cookies[tokenCookieName] - } - } + const cookies = parseCookies(req) + const tokenCookieName = `${config.cookiePrefix}-token` + + if (!cookies?.[tokenCookieName]) { + return null + } + + if (!origin || config.csrf.length === 0 || config.csrf.indexOf(origin) > -1) { + return cookies[tokenCookieName] } return null