FlowiseAI/Flowise · error · Error

Access token is expired and no refresh token is available. P

Error message

Access token is expired and no refresh token is available. Please re-authorize the credential.

What it means

Thrown by refreshOAuth2Token when credentialData.expires_at indicates the token is past the buffer window (5 min default) AND credentialData.refresh_token is absent. There is no way to silently refresh, so the only recovery is interactive re-authorization of the OAuth2 credential.

Source

Thrown at packages/components/src/utils.ts:1467

 * @param {ICommonObject} credentialData
 * @param {ICommonObject} options
 * @param {number} bufferTimeMs - Buffer time in milliseconds before expiry (default: 5 minutes)
 * @returns {Promise<ICommonObject>}
 */
export const refreshOAuth2Token = async (
    credentialId: string,
    credentialData: ICommonObject,
    options: ICommonObject,
    bufferTimeMs: number = 5 * 60 * 1000
): Promise<ICommonObject> => {
    // Check if token is expired and refresh if needed
    if (credentialData.expires_at) {
        const expiryTime = new Date(credentialData.expires_at)
        const currentTime = new Date()

        if (currentTime.getTime() > expiryTime.getTime() - bufferTimeMs) {
            if (!credentialData.refresh_token) {
                throw new Error('Access token is expired and no refresh token is available. Please re-authorize the credential.')
            }

            try {
                // Import fetch dynamically to avoid issues
                const fetch = (await import('node-fetch')).default

                // Call the refresh API endpoint
                const refreshResponse = await fetch(
                    `${options.baseURL || 'http://localhost:3000'}/api/v1/oauth2-credential/refresh/${credentialId}`,
                    {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        }
                    }
                )

                if (!refreshResponse.ok) {

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Re-authorize the OAuth2 credential through Flowise to obtain a fresh access + refresh token pair.
  2. When authorizing, request the offline_access / appropriate scope so the provider issues a refresh_token.
  3. Ensure the credential persistence layer stores the refresh_token returned by each refresh (rotate single-use refresh tokens).
  4. Increase bufferTimeMs if the issue is clock skew between Flowise and the provider.

Example fix

// before
if (!credentialData.refresh_token) {
  throw new Error('Access token is expired and no refresh token is available. Please re-authorize the credential.')
}

// after — actionable message with the provider context
if (!credentialData.refresh_token) {
  throw new Error(
    `Access token for credential ${credentialId} expired at ${credentialData.expires_at} and no refresh_token is stored. ` +
    `Re-authorize the credential and ensure the OAuth scope includes offline_access/refresh_tokens.`
  )
}
Defensive patterns

Strategy: validation

Validate before calling

function canRefreshOAuth2(cred: ICommonObject): boolean {
  return Boolean(cred && typeof cred.refresh_token === 'string' && cred.refresh_token.length > 0)
}

Type guard

function hasRefreshToken(cred: unknown): cred is { refresh_token: string; expires_at?: string } {
  return typeof cred === 'object' && cred !== null && typeof (cred as any).refresh_token === 'string'
}

Try / catch

if (currentTime.getTime() > expiryTime.getTime() - bufferTimeMs) {
  if (!hasRefreshToken(credentialData)) {
    throw new Error(`Access token expired at ${credentialData.expires_at}; no refresh_token stored. Re-authorize credential ${credentialId}.`)
  }
  // proceed with refresh
}

Prevention

When it happens

Trigger: The OAuth2 provider did not return a refresh_token at authorization time (some scopes/server flows omit it); the refresh_token was dropped during credential storage/serialization; the credential was authorized with a grant type that doesn't issue refresh tokens (e.g. implicit); a previous refresh consumed a single-use refresh token that wasn't persisted back.

Common situations: Google/Microsoft OAuth where offline_access scope wasn't requested; the provider's refresh token is single-use and the new one wasn't saved after the last refresh; credentials imported/exported without the refresh_token field; token expiry after a long Flowise downtime.

Understand the failure class

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/6db49d126c0f3db7. Report an issue: GitHub.