chore(plugin-cloud): refresh session on ExpiredToken error code (#8904)

Fixes https://github.com/payloadcms/payload/issues/8404

This code will refresh the session token upon receiving an
`ExpiredToken` error when `storageClient.getObject()` receives that
error.

- The `Error Code` detected is determined by the error reported in the
issue, and is an actual code from [AWS
documentation](https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html)
for Error Responses.

- If the request fails again, the error is thrown.
This commit is contained in:
Kendell Joseph
2025-02-25 09:17:30 -05:00
committed by GitHub
parent 7bb1c9d3c6
commit 1e698c2bdf
2 changed files with 54 additions and 40 deletions

View File

@@ -1,19 +1,13 @@
import type * as AWS from '@aws-sdk/client-s3'
import type { CognitoUserSession } from 'amazon-cognito-identity-js'
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity'
import * as AWS from '@aws-sdk/client-s3'
import { fromCognitoIdentityPool } from '@aws-sdk/credential-providers'
import type { GetStorageClient } from './refreshSession.js'
import { authAsCognitoUser } from './authAsCognitoUser.js'
import { refreshSession } from './refreshSession.js'
export type GetStorageClient = () => Promise<{
identityID: string
storageClient: AWS.S3
}>
let storageClient: AWS.S3 | null = null
let session: CognitoUserSession | null = null
let identityID: string
export let storageClient: AWS.S3 | null = null
export let session: CognitoUserSession | null = null
export let identityID: string
export const getStorageClient: GetStorageClient = async () => {
if (storageClient && session?.isValid()) {
@@ -23,6 +17,8 @@ export const getStorageClient: GetStorageClient = async () => {
}
}
;({ identityID, session, storageClient } = await refreshSession())
if (!process.env.PAYLOAD_CLOUD_PROJECT_ID) {
throw new Error('PAYLOAD_CLOUD_PROJECT_ID is required')
}
@@ -33,34 +29,6 @@ export const getStorageClient: GetStorageClient = async () => {
throw new Error('PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID is required')
}
session = await authAsCognitoUser(
process.env.PAYLOAD_CLOUD_PROJECT_ID,
process.env.PAYLOAD_CLOUD_COGNITO_PASSWORD,
)
const cognitoIdentity = new CognitoIdentityClient({
credentials: fromCognitoIdentityPool({
clientConfig: {
region: 'us-east-1',
},
identityPoolId: process.env.PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID,
logins: {
[`cognito-idp.us-east-1.amazonaws.com/${process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID}`]:
session.getIdToken().getJwtToken(),
},
}),
})
const credentials = await cognitoIdentity.config.credentials()
// @ts-expect-error - Incorrect AWS types
identityID = credentials.identityId
storageClient = new AWS.S3({
credentials,
region: process.env.PAYLOAD_CLOUD_BUCKET_REGION,
})
return {
identityID,
storageClient,

View File

@@ -0,0 +1,46 @@
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity'
import * as AWS from '@aws-sdk/client-s3'
import { fromCognitoIdentityPool } from '@aws-sdk/credential-providers'
import { authAsCognitoUser } from './authAsCognitoUser.js'
export type GetStorageClient = () => Promise<{
identityID: string
storageClient: AWS.S3
}>
export const refreshSession = async () => {
const session = await authAsCognitoUser(
process.env.PAYLOAD_CLOUD_PROJECT_ID || '',
process.env.PAYLOAD_CLOUD_COGNITO_PASSWORD || '',
)
const cognitoIdentity = new CognitoIdentityClient({
credentials: fromCognitoIdentityPool({
clientConfig: {
region: 'us-east-1',
},
identityPoolId: process.env.PAYLOAD_CLOUD_COGNITO_IDENTITY_POOL_ID || '',
logins: {
[`cognito-idp.us-east-1.amazonaws.com/${process.env.PAYLOAD_CLOUD_COGNITO_USER_POOL_ID}`]:
session.getIdToken().getJwtToken(),
},
}),
})
const credentials = await cognitoIdentity.config.credentials()
// @ts-expect-error - Incorrect AWS types
const identityID = credentials.identityId
const storageClient = new AWS.S3({
credentials,
region: process.env.PAYLOAD_CLOUD_BUCKET_REGION,
})
return {
identityID,
session,
storageClient,
}
}