[PR #3649] [MERGED] fix: generic oauth plugin - accountId database fix #13181

Closed
opened 2026-04-13 08:48:48 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/3649
Author: @charlietlamb
Created: 7/27/2025
Status: Merged
Merged: 8/6/2025
Merged by: @Bekacru

Base: canaryHead: account-id-fix


📝 Commits (3)

  • b925403 fix: generic oauth plugin - set account id from mapped user fields when creating account
  • 2c78a3e chore: add changeset
  • 382613c chore: remove changeset

📊 Changes

1 file changed (+1 additions, -1 deletions)

View changed files

📝 packages/better-auth/src/plugins/generic-oauth/index.ts (+1 -1)

📄 Description

I found this bug when trying to integrate with a custom atlassian oauth provider.

The userInfoUrl for this provider is https://api.atlassian.com/me which returns this response:

{
  id: undefined,
  emailVerified: true,
  email: '<my-email>',
  image: '<my-image>',
  name: 'Charlie Lamb',
  account_id: '<my-account-id>',
  picture: '<my-pic>',
  account_status: 'active',
  characteristics: { not_mentionable: false },
  last_updated: '2025-07-26T11:47:22.387Z',
  nickname: 'Charlie Lamb',
  locale: 'en-GB',
  extended_profile: { phone_numbers: [], team_type: 'Software Development' },
  account_type: 'atlassian',
  email_verified: true
}

You can see the id field is undefined - this meant I was getting this error when trying to create an account based on this response.

  query: 'insert into "accounts" ("id", "account_id", "provider_id", "user_id", "access_token", "refresh_token", "id_token", "access_token_expires_at", "refresh_token_expires_at", "scope", "password", "created_at", "updated_at") values ($1, default, $2, $3, $4, default, default, $5, default, $6, default, $7, $8) returning "id", "account_id", "provider_id", "user_id", "access_token", "refresh_token", "id_token", "access_token_expires_at", "refresh_token_expires_at", "scope", "password", "created_at", "updated_at"',
  params: [Array],
  [cause]: [error: null value in column "account_id" of relation "accounts" violates not-null constraint] {
    length: 524,
    severity: 'ERROR',
    code: '23502',
    detail: 'Failing row contains (kj2QbwVTbCMCjlVkiITbtl2UQBqlr3tG, null, atlassian, B3zfFD9aXby2uLdXS5YiQ6LyPyW5Pjxn, eyJraWQiOiJhdXRoLmF0bGFzc2lhbi5jb20tQUNDRVNTLTk0ZTczYTkwLTUxYWQt..., null, null, 2025-07-27 14:43:07.107, null, manage:jira-configuration,manage:jira-project,manage:jira-webhoo..., null, 2025-07-27 13:43:07.259, 2025-07-27 13:43:07.259).',
    hint: undefined,
    position: undefined,
    internalPosition: undefined,
    internalQuery: undefined,
    where: undefined,
    schema: 'public',
    table: 'accounts',
    column: 'account_id',
    dataType: undefined,
    constraint: undefined,
    file: 'execMain.c',
    line: '1972',
    routine: 'ExecConstraints'
  }
}

hence I tried to fix this with the following confiugration

My genericOAuth config:

    genericOAuth({
      config: [
        {
          providerId: 'atlassian',
          clientId: env.ATLASSIAN_CLIENT_ID,
          clientSecret: env.ATLASSIAN_CLIENT_SECRET,
          authorizationUrl: 'https://auth.atlassian.com/authorize',
          tokenUrl: 'https://auth.atlassian.com/oauth/token',
          scopes: [
            'read:jira-user',
            'read:jira-work',
            'write:jira-work',
            'manage:jira-project',
            'manage:jira-configuration',
            'manage:jira-webhook',
            'read:me',
            'read:account',
          ],
          userInfoUrl: 'https://api.atlassian.com/me',
          mapProfileToUser: (profile) => {
            const atlassianProfile = profile as AtlassianAccount;
            return {
              ...atlassianProfile,
              id: atlassianProfile.account_id,
            };
          },
        },
      ],
    }),

However as you can see in my pull request this didn't work as the createAccount method uses

accountId: userInfo.id,

instead we need this so that an override works

accountId: mapUser.id,

to get around this issue I currently have to do the following:

          getUserInfo: async (tokens) => {
            const response = await fetch('https://api.atlassian.com/me', {
              headers: {
                Authorization: `Bearer ${tokens.accessToken}`,
              },
            });
            const data: AtlassianAccount = await response.json();
            return {
              ...data,
              id: data.account_id,
            };
          },

Summary by cubic

Fixed a bug in the generic OAuth plugin where the account ID was not set correctly if the user profile lacked an id field. Now, account creation uses the mapped user id if available, preventing database errors with providers like Atlassian.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/3649 **Author:** [@charlietlamb](https://github.com/charlietlamb) **Created:** 7/27/2025 **Status:** ✅ Merged **Merged:** 8/6/2025 **Merged by:** [@Bekacru](https://github.com/Bekacru) **Base:** `canary` ← **Head:** `account-id-fix` --- ### 📝 Commits (3) - [`b925403`](https://github.com/better-auth/better-auth/commit/b925403c5b40a324a376c708ec5591c2fc402990) fix: generic oauth plugin - set account id from mapped user fields when creating account - [`2c78a3e`](https://github.com/better-auth/better-auth/commit/2c78a3edd679b1b76db481ff7b644e952d7c0372) chore: add changeset - [`382613c`](https://github.com/better-auth/better-auth/commit/382613c2131eab6c664c8eca81ae0d5d362f5c02) chore: remove changeset ### 📊 Changes **1 file changed** (+1 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/plugins/generic-oauth/index.ts` (+1 -1) </details> ### 📄 Description I found this bug when trying to integrate with a custom `atlassian` oauth provider. The `userInfoUrl` for this provider is `https://api.atlassian.com/me` which returns this response: ``` { id: undefined, emailVerified: true, email: '<my-email>', image: '<my-image>', name: 'Charlie Lamb', account_id: '<my-account-id>', picture: '<my-pic>', account_status: 'active', characteristics: { not_mentionable: false }, last_updated: '2025-07-26T11:47:22.387Z', nickname: 'Charlie Lamb', locale: 'en-GB', extended_profile: { phone_numbers: [], team_type: 'Software Development' }, account_type: 'atlassian', email_verified: true } ``` You can see the `id` field is undefined - this meant I was getting this error when trying to create an account based on this response. ``` query: 'insert into "accounts" ("id", "account_id", "provider_id", "user_id", "access_token", "refresh_token", "id_token", "access_token_expires_at", "refresh_token_expires_at", "scope", "password", "created_at", "updated_at") values ($1, default, $2, $3, $4, default, default, $5, default, $6, default, $7, $8) returning "id", "account_id", "provider_id", "user_id", "access_token", "refresh_token", "id_token", "access_token_expires_at", "refresh_token_expires_at", "scope", "password", "created_at", "updated_at"', params: [Array], [cause]: [error: null value in column "account_id" of relation "accounts" violates not-null constraint] { length: 524, severity: 'ERROR', code: '23502', detail: 'Failing row contains (kj2QbwVTbCMCjlVkiITbtl2UQBqlr3tG, null, atlassian, B3zfFD9aXby2uLdXS5YiQ6LyPyW5Pjxn, eyJraWQiOiJhdXRoLmF0bGFzc2lhbi5jb20tQUNDRVNTLTk0ZTczYTkwLTUxYWQt..., null, null, 2025-07-27 14:43:07.107, null, manage:jira-configuration,manage:jira-project,manage:jira-webhoo..., null, 2025-07-27 13:43:07.259, 2025-07-27 13:43:07.259).', hint: undefined, position: undefined, internalPosition: undefined, internalQuery: undefined, where: undefined, schema: 'public', table: 'accounts', column: 'account_id', dataType: undefined, constraint: undefined, file: 'execMain.c', line: '1972', routine: 'ExecConstraints' } } ``` hence I tried to fix this with the following confiugration My `genericOAuth` config: ``` genericOAuth({ config: [ { providerId: 'atlassian', clientId: env.ATLASSIAN_CLIENT_ID, clientSecret: env.ATLASSIAN_CLIENT_SECRET, authorizationUrl: 'https://auth.atlassian.com/authorize', tokenUrl: 'https://auth.atlassian.com/oauth/token', scopes: [ 'read:jira-user', 'read:jira-work', 'write:jira-work', 'manage:jira-project', 'manage:jira-configuration', 'manage:jira-webhook', 'read:me', 'read:account', ], userInfoUrl: 'https://api.atlassian.com/me', mapProfileToUser: (profile) => { const atlassianProfile = profile as AtlassianAccount; return { ...atlassianProfile, id: atlassianProfile.account_id, }; }, }, ], }), ``` However as you can see in my pull request this didn't work as the `createAccount` method uses ``` accountId: userInfo.id, ``` instead we need this so that an override works ``` accountId: mapUser.id, ``` to get around this issue I currently have to do the following: ``` getUserInfo: async (tokens) => { const response = await fetch('https://api.atlassian.com/me', { headers: { Authorization: `Bearer ${tokens.accessToken}`, }, }); const data: AtlassianAccount = await response.json(); return { ...data, id: data.account_id, }; }, ``` <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixed a bug in the generic OAuth plugin where the account ID was not set correctly if the user profile lacked an id field. Now, account creation uses the mapped user id if available, preventing database errors with providers like Atlassian. <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-13 08:48:48 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#13181