Budibase/budibase · error

No refresh token found for authenticated user

Error message

No refresh token found for authenticated user

What it means

When executing an OAuth2-authenticated query whose token has expired, the thread attempts refreshOAuth2 to obtain a new access token using the user's stored refresh token. If the request context has no providerType or the oauth2 object lacks a refreshToken, a plain Error 'No refresh token found for authenticated user' is thrown, so the query cannot be authenticated.

Source

Thrown at packages/server/src/threads/query.ts:350

        queryVerb: query.queryVerb,
        fields: query.fields,
        transformer: query.transformer,
        nullDefaultSupport: query.nullDefaultSupport,
        ctx: this.ctx,
        parameters: currentParameters,
        datasource,
        queryId,
      },
      { noRecursiveQuery: true }
    ).execute()
  }

  async refreshOAuth2(ctx: any) {
    const { oauth2, providerType, _id } = ctx.user
    const { configId } = ctx.auth

    if (!providerType || !oauth2?.refreshToken) {
      throw new Error("No refresh token found for authenticated user")
    }

    const resp = await auth.refreshOAuthToken(
      oauth2.refreshToken,
      providerType,
      configId
    )

    // Refresh session flow. Should be in same location as refreshOAuthToken
    // There are several other properties available in 'resp'
    if (!resp.err) {
      const globalUserId = getGlobalIDFromUserMetadataID(_id)
      await auth.updateUserOAuth(globalUserId, resp)
      if (!this.ctx) {
        this.ctx = {}
      }
      this.ctx.user = (await cache.user.getUser({
        userId: globalUserId,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Re-authenticate the user with the OAuth2 provider so a fresh refresh token is stored, then retry the query
  2. Verify the OAuth2 config requests the offline_access/refresh scope so a refresh token is issued
  3. Check ctx.user.oauth2 and providerType are populated before executing OAuth2 queries; clear stale auth config and re-create it
  4. Confirm the refresh token wasn't revoked in the provider's admin console

Example fix

// before
const resp = await api.executeQueryableQuery(...) // throws: no refresh token
// after
if (!ctx.user?.oauth2?.refreshToken) {
  await reauthenticateUser(configId) // re-run OAuth2 flow to store a refresh token
}
const resp = await api.executeQueryableQuery(...)
Defensive patterns

Strategy: try-catch

Validate before calling

const { oauth2, providerType } = user
if (!providerType || !oauth2?.refreshToken) {
  await reauthenticateUser(user) // run OAuth2 flow to obtain a refresh token
}

Type guard

function hasRefreshToken(user) {
  return typeof user?.providerType === 'string' && typeof user?.oauth2?.refreshToken === 'string' && user.oauth2.refreshToken.length > 0
}

Try / catch

try {
  await sdk.queries.execute(queryId, params)
} catch (e) {
  if (e?.message?.includes('No refresh token found for authenticated user')) {
    await reauthenticateUser(user) // then retry once
  } else throw e
}

Prevention

When it happens

Trigger: Executing a query against an OAuth2 datasource when ctx.user.oauth2.refreshToken is undefined (user authenticated without a refresh token / token already consumed and not re-stored) or providerType is missing from ctx.user.

Common situations: OAuth provider configured without offline access / refresh token scope; refresh token revoked or expired server-side and never refreshed; auth config (configId) changed so stored tokens no longer match; user session created before OAuth2 was configured on the datasource.

Understand the failure class

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/25642b84e7e61495. Report an issue: GitHub.