fix: auth strategy exp (#6945)
## Description Ensures that exp and auth strategy are available from the `me` and `refresh` operations as well as passed through the `Auth` provider. Same as #6943 - [x] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue)
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
import type { Collection } from 'payload'
|
||||
|
||||
import { isolateObjectProperty, meOperation } from 'payload'
|
||||
import { extractJWT, isolateObjectProperty, meOperation } from 'payload'
|
||||
|
||||
import type { Context } from '../types.js'
|
||||
|
||||
function meResolver(collection: Collection): any {
|
||||
async function resolver(_, args, context: Context) {
|
||||
const currentToken = extractJWT(context.req)
|
||||
|
||||
const options = {
|
||||
collection,
|
||||
currentToken,
|
||||
depth: 0,
|
||||
req: isolateObjectProperty(context.req, 'transactionID'),
|
||||
}
|
||||
|
||||
const result = await meOperation(options)
|
||||
|
||||
if (collection.config.auth.removeTokenFromResponses) {
|
||||
|
||||
@@ -379,6 +379,9 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
exp: {
|
||||
type: GraphQLInt,
|
||||
},
|
||||
strategy: {
|
||||
type: GraphQLString,
|
||||
},
|
||||
token: {
|
||||
type: GraphQLString,
|
||||
},
|
||||
@@ -405,6 +408,9 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
refreshedToken: {
|
||||
type: GraphQLString,
|
||||
},
|
||||
strategy: {
|
||||
type: GraphQLString,
|
||||
},
|
||||
user: {
|
||||
type: collection.graphQL.JWT,
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { ClientUser, User } from '../types.js'
|
||||
export type MeOperationResult = {
|
||||
collection?: string
|
||||
exp?: number
|
||||
strategy?: string
|
||||
token?: string
|
||||
user?: ClientUser
|
||||
}
|
||||
@@ -49,6 +50,7 @@ export const meOperation = async ({
|
||||
|
||||
result = {
|
||||
collection: req.user.collection,
|
||||
strategy: req.user._strategy,
|
||||
user,
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { getFieldsToSign } from '../getFieldsToSign.js'
|
||||
export type Result = {
|
||||
exp: number
|
||||
refreshedToken: string
|
||||
strategy?: string
|
||||
user: Document
|
||||
}
|
||||
|
||||
@@ -88,6 +89,7 @@ export const refreshOperation = async (incomingArgs: Arguments): Promise<Result>
|
||||
let result: Result = {
|
||||
exp,
|
||||
refreshedToken,
|
||||
strategy: args.req.user._strategy,
|
||||
user,
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export type AuthContext<T = ClientUser> = {
|
||||
refreshPermissions: () => Promise<void>
|
||||
setPermissions: (permissions: Permissions) => void
|
||||
setUser: (user: T) => void
|
||||
strategy?: string
|
||||
token?: string
|
||||
tokenExpiration?: number
|
||||
user?: T | null
|
||||
}
|
||||
|
||||
@@ -36,6 +38,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const [user, setUser] = useState<ClientUser | null>()
|
||||
const [tokenInMemory, setTokenInMemory] = useState<string>()
|
||||
const [tokenExpiration, setTokenExpiration] = useState<number>()
|
||||
const [strategy, setStrategy] = useState<string>()
|
||||
const pathname = usePathname()
|
||||
const router = useRouter()
|
||||
// const { code } = useLocale()
|
||||
@@ -76,6 +79,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const revokeTokenAndExpire = useCallback(() => {
|
||||
setTokenInMemory(undefined)
|
||||
setTokenExpiration(undefined)
|
||||
setStrategy(undefined)
|
||||
}, [])
|
||||
|
||||
const setTokenAndExpiration = useCallback(
|
||||
@@ -84,6 +88,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
if (token && json?.exp) {
|
||||
setTokenInMemory(token)
|
||||
setTokenExpiration(json.exp)
|
||||
if (json.strategy) setStrategy(json.strategy)
|
||||
} else {
|
||||
revokeTokenAndExpire()
|
||||
}
|
||||
@@ -258,6 +263,8 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
searchParams,
|
||||
admin,
|
||||
revokeTokenAndExpire,
|
||||
strategy,
|
||||
tokenExpiration,
|
||||
loginRoute,
|
||||
])
|
||||
|
||||
|
||||
@@ -8,122 +8,123 @@
|
||||
|
||||
export interface Config {
|
||||
collections: {
|
||||
posts: Post
|
||||
users: User
|
||||
'payload-preferences': PayloadPreference
|
||||
'payload-migrations': PayloadMigration
|
||||
}
|
||||
posts: Post;
|
||||
users: User;
|
||||
'payload-preferences': PayloadPreference;
|
||||
'payload-migrations': PayloadMigration;
|
||||
};
|
||||
globals: {
|
||||
menu: Menu
|
||||
}
|
||||
locale: null
|
||||
menu: Menu;
|
||||
};
|
||||
locale: null;
|
||||
user: User & {
|
||||
collection: 'users'
|
||||
}
|
||||
collection: 'users';
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts".
|
||||
*/
|
||||
export interface Post {
|
||||
id: string
|
||||
text?: string | null
|
||||
id: string;
|
||||
text?: string | null;
|
||||
richText?: {
|
||||
root: {
|
||||
type: string
|
||||
type: string;
|
||||
children: {
|
||||
type: string
|
||||
version: number
|
||||
[k: string]: unknown
|
||||
}[]
|
||||
direction: ('ltr' | 'rtl') | null
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
|
||||
indent: number
|
||||
version: number
|
||||
}
|
||||
[k: string]: unknown
|
||||
} | null
|
||||
type: string;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
richText2?: {
|
||||
root: {
|
||||
type: string
|
||||
type: string;
|
||||
children: {
|
||||
type: string
|
||||
version: number
|
||||
[k: string]: unknown
|
||||
}[]
|
||||
direction: ('ltr' | 'rtl') | null
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
|
||||
indent: number
|
||||
version: number
|
||||
}
|
||||
[k: string]: unknown
|
||||
} | null
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
_status?: ('draft' | 'published') | null
|
||||
type: string;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users".
|
||||
*/
|
||||
export interface User {
|
||||
id: string
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
email: string
|
||||
resetPasswordToken?: string | null
|
||||
resetPasswordExpiration?: string | null
|
||||
salt?: string | null
|
||||
hash?: string | null
|
||||
loginAttempts?: number | null
|
||||
lockUntil?: string | null
|
||||
password?: string | null
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
email: string;
|
||||
resetPasswordToken?: string | null;
|
||||
resetPasswordExpiration?: string | null;
|
||||
salt?: string | null;
|
||||
hash?: string | null;
|
||||
loginAttempts?: number | null;
|
||||
lockUntil?: string | null;
|
||||
password?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-preferences".
|
||||
*/
|
||||
export interface PayloadPreference {
|
||||
id: string
|
||||
id: string;
|
||||
user: {
|
||||
relationTo: 'users'
|
||||
value: string | User
|
||||
}
|
||||
key?: string | null
|
||||
relationTo: 'users';
|
||||
value: string | User;
|
||||
};
|
||||
key?: string | null;
|
||||
value?:
|
||||
| {
|
||||
[k: string]: unknown
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "payload-migrations".
|
||||
*/
|
||||
export interface PayloadMigration {
|
||||
id: string
|
||||
name?: string | null
|
||||
batch?: number | null
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
id: string;
|
||||
name?: string | null;
|
||||
batch?: number | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "menu".
|
||||
*/
|
||||
export interface Menu {
|
||||
id: string
|
||||
globalText?: string | null
|
||||
updatedAt?: string | null
|
||||
createdAt?: string | null
|
||||
id: string;
|
||||
globalText?: string | null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
|
||||
|
||||
declare module 'payload' {
|
||||
// @ts-ignore
|
||||
export interface GeneratedTypes extends Config {}
|
||||
|
||||
@@ -134,6 +134,8 @@ describe('Auth', () => {
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
expect(data.strategy).toBeDefined()
|
||||
expect(typeof data.exp).toBe('number')
|
||||
expect(response.status).toBe(200)
|
||||
expect(data.user.email).toBeDefined()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user