Skip to content

feat(core): introduce experimental refreshUserInfo APIs - #219

Merged
halvaradop merged 4 commits into
masterfrom
feat/add-refresh-user-info-apis
Jul 9, 2026
Merged

feat(core): introduce experimental refreshUserInfo APIs#219
halvaradop merged 4 commits into
masterfrom
feat/add-refresh-user-info-apis

Conversation

@halvaradop

@halvaradop halvaradop commented Jul 8, 2026

Copy link
Copy Markdown
Member

Description

This pull request introduces the experimental refreshUserInfo() API for both server-side and client-side applications.

The new API allows applications to refresh a user's profile information and update the current session without requiring the user to sign in again. It fetches the latest user information from the OAuth or OpenID Connect (OIDC) provider's configured userInfo endpoint, reconstructs the user profile using the provider's profile mapping function, and updates the session with the refreshed data.

On the server, the functionality is exposed through auth.api.refreshUserInfo(). On the client, createAuthClient().refreshUserInfo() communicates with the POST /providers/:provider/user/refresh endpoint to perform the same operation.

Usage

Server-side

import { createAuth } from "@aura-stack/auth"

export const auth = createAuth({
  oauth: ["google"],
})

const { success, session } = await auth.api.refreshUserInfo("google")

Client-side

import { createAuthClient } from "@aura-stack/auth/client"

export const authClient = createAuthClient({})

const session = await authClient.refreshUserInfo("google")

Note

refreshUserInfo() requires the configured provider to expose a userInfo endpoint. Providers that do not implement user information retrieval cannot support this feature.

@coderabbitai ignore

@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
auth Skipped Skipped Jul 9, 2026 9:04pm

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds refresh-userinfo support across the auth core package, including new API contracts, server and client entry points, route wiring, rate-limit handling, error codes, supporting utilities, and test coverage.

Changes

refreshUserInfo API implementation

Layer / File(s) Summary
Types, errors, and rate limits
packages/core/src/@types/api.ts, packages/core/src/@types/config.ts, packages/core/src/shared/errors.ts, packages/core/CHANGELOG.md
Adds RefreshUserInfoAPIOptions/RefreshUserInfoData/RefreshUserInfoAPIReturn, widens RateLimiterConfig.rules for refreshUserInfo, adds three refresh-related error codes and catalog entries, and updates the changelog.
Userinfo logging and session merge
packages/core/src/actions/callback/userinfo.ts, packages/core/src/shared/utils.ts
Updates userinfo error logging with structured error metadata, adds merge(), and types createStandardSession’s identity parameter as SchemaRegistryContext.
refreshUserInfo API logic
packages/core/src/api/refreshUserInfo.ts
Implements the refresh flow: provider lookup, session/CSRF validation, rate-limit checks, token retrieval, userinfo fetch, session creation, and success/failure toResponse() output.
Route and client wiring
packages/core/src/actions/user/refresh.ts, packages/core/src/createAuth.ts, packages/core/src/api/createApi.ts, packages/core/src/client/client.ts, packages/core/src/router/rate-limiter.ts
Adds the POST refresh action, registers it in auth setup, exposes the server API method, adds the client method, and updates rate-limit execution defaults for refresh failures.
refreshUserInfo tests
packages/core/test/actions/user/refresh.test.ts, packages/core/test/api/refreshUserInfo.test.ts
Adds Vitest coverage for refresh routing, validation, provider/token failures, success cases, cookie updates, custom profile mapping, and response bodies.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: feature, experimental

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding experimental refreshUserInfo APIs in core.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-refresh-user-info-apis

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
packages/core/src/shared/errors.ts (1)

843-850: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clarify awkward message phrasing.

The INVALID_REFRESH_USER_INFO_RESPONSE catalog message contains "during a synchronization sync block" which is redundant and unclear. Consider simplifying to something like "during a profile synchronization request."

💬 Suggested rewording
         message:
-            "The outbound HTTP request to the provider user info profile endpoint returned a non-2xx status code during a synchronization sync block. The response 'ok' field resolved to false.",
+            "The outbound HTTP request to the provider user info profile endpoint returned a non-2xx status code during a profile synchronization request. The response 'ok' field resolved to false.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/shared/errors.ts` around lines 843 - 850, The
INVALID_REFRESH_USER_INFO_RESPONSE catalog message has awkward redundant wording
(“synchronization sync block”) that should be simplified. Update the message
string in the errors catalog entry to use clearer phrasing, such as referring to
a profile synchronization request, and keep the change localized to the
INVALID_REFRESH_USER_INFO_RESPONSE definition so the AuthError metadata stays
unchanged.
packages/core/src/router/rate-limiter.ts (1)

79-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding an explicit return type to verifyRateLimit.

defaultValues returns a union of different object shapes depending on action, and verifyRateLimit's return type is inferred. This creates a type-safety gap at call sites, which are already worked around with as casts (e.g., rateLimit as RefreshUserInfoAPIReturn<DefaultUser>). Adding an explicit return type or a generic parameter would surface mismatches at compile time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/router/rate-limiter.ts` around lines 79 - 94, The return
type of verifyRateLimit is currently inferred, which hides shape mismatches from
defaultValues and forces unsafe casts at call sites. Add an explicit return type
for verifyRateLimit, preferably a generic that ties the action key to the
corresponding RateLimiterConfig/defaultValues shape, and keep the success/error
object consistent with that type. Use verifyRateLimit and defaultValues as the
main symbols when updating the signature so compile-time checks catch invalid
combinations instead of relying on as casts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/actions/callback/userinfo.ts`:
- Line 86: Remove the stray debug console output in the user info error path and
use the existing structured logger instead. In the error handling inside the
userinfo action, delete the console.log call and, if error details are needed,
attach them to the existing logger?.log("OAUTH_USERINFO_REQUEST_FAILED") call
via structuredData so the failure is recorded without polluting stdout or
leaking provider details.

In `@packages/core/src/api/refreshUserInfo.ts`:
- Line 72: Rename the refresh-user-info auth error code to use the correct
spelling everywhere it is defined and thrown: update the AuraAuthError code in
refreshUserInfo and the matching catalog entry in shared/errors so both use
INVALID_ACCESS_TOKEN_RETRIEVING_REFRESH_USER_INFO instead of
INVALID_ACCESS_TOKEN_RETRIVING_REFRESH_USER_INFO. Keep the symbol names
AuraAuthError, refreshUserInfo, and the error catalog entry in sync so the code
and lookup remain consistent.
- Around line 75-86: The `getUserInfo` call in `refreshUserInfo` is passing the
wrong value for `expires_in`: `AccessTokenContext.expiresIn` expects a relative
lifetime in seconds, but the code is using the absolute `tokens.expiresAt`
timestamp. Update the `userInfo.request` payload construction in
`refreshUserInfo` so `expires_in` is derived from the token’s remaining lifetime
rather than `expiresAt`, and keep the mapping aligned with the `tokens` fields
used alongside `access_token`, `refresh_token`, and `id_token`.

In `@packages/core/src/router/rate-limiter.ts`:
- Around line 62-74: Add a dedicated `defaultValues()` branch for
`getProviderTokens` in `rate-limiter.ts`; the current default payload omits the
`tokens` field, so rate-limited failures won’t match the expected shape. Update
the `switch` in `defaultValues(action)` to return `tokens: null` for
`getProviderTokens`, while keeping the existing behavior for `refreshUserInfo`,
`signIn`, `signInCredentials`, `signUp`, and `updateSession`.

In `@packages/core/src/shared/errors.ts`:
- Line 119: The error code constant has a typo in its name: update the
INVALID_ACCESS_TOKEN_RETRIVING_REFRESH_USER_INFO symbol in the errors catalog to
INVALID_ACCESS_TOKEN_RETRIEVING_REFRESH_USER_INFO, and then update every
matching reference in the auth error path, including the AuraAuthError throw
site(s), so the exported API name stays consistent everywhere.

In `@packages/core/test/api/refreshUserInfo.test.ts`:
- Around line 11-13: The test cleanup in afterEach only resets environment
stubs, so global stubs like fetch can leak between tests. Update the existing
afterEach in refreshUserInfo.test.ts to also call vi.unstubAllGlobals()
alongside vi.unstubAllEnvs(), so all vi.stubGlobal usage is properly restored
after each test.
- Around line 246-259: The mocked getUserInfo success responses are missing
headers, which causes response.headers.get("Content-Type") to throw before the
intended OAuth error handling runs. Update the ok: true fetch mocks in
refreshUserInfo.test.ts to include a Headers object with Content-Type set to
application/json so the getUserInfo path can parse the response and reach the
expected error assertion. Use the getUserInfo mock response setup in the
relevant test cases to locate and fix both affected mocks.

---

Nitpick comments:
In `@packages/core/src/router/rate-limiter.ts`:
- Around line 79-94: The return type of verifyRateLimit is currently inferred,
which hides shape mismatches from defaultValues and forces unsafe casts at call
sites. Add an explicit return type for verifyRateLimit, preferably a generic
that ties the action key to the corresponding RateLimiterConfig/defaultValues
shape, and keep the success/error object consistent with that type. Use
verifyRateLimit and defaultValues as the main symbols when updating the
signature so compile-time checks catch invalid combinations instead of relying
on as casts.

In `@packages/core/src/shared/errors.ts`:
- Around line 843-850: The INVALID_REFRESH_USER_INFO_RESPONSE catalog message
has awkward redundant wording (“synchronization sync block”) that should be
simplified. Update the message string in the errors catalog entry to use clearer
phrasing, such as referring to a profile synchronization request, and keep the
change localized to the INVALID_REFRESH_USER_INFO_RESPONSE definition so the
AuthError metadata stays unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7127d6d-1d3d-4e8f-81f9-7a4009cc17ed

📥 Commits

Reviewing files that changed from the base of the PR and between 8909d6d and d0578c5.

📒 Files selected for processing (9)
  • packages/core/src/@types/api.ts
  • packages/core/src/@types/config.ts
  • packages/core/src/actions/callback/userinfo.ts
  • packages/core/src/api/createApi.ts
  • packages/core/src/api/refreshUserInfo.ts
  • packages/core/src/router/rate-limiter.ts
  • packages/core/src/shared/errors.ts
  • packages/core/src/shared/utils.ts
  • packages/core/test/api/refreshUserInfo.test.ts

Comment thread packages/core/src/actions/callback/userinfo.ts Outdated
Comment thread packages/core/src/api/refreshUserInfo.ts Outdated
Comment thread packages/core/src/api/refreshUserInfo.ts
Comment thread packages/core/src/router/rate-limiter.ts
Comment thread packages/core/src/shared/errors.ts Outdated
Comment thread packages/core/test/api/refreshUserInfo.test.ts
Comment thread packages/core/test/api/refreshUserInfo.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/actions/user/refresh.ts`:
- Around line 10-13: The z.enum() call in the user refresh action is using the
old string-based second argument, which is no longer valid in Zod 4. Update the
oauth schema in refresh.ts to pass the message through the Zod error object
format, using the existing “The OAuth provider is not supported or invalid.”
text, and keep the change localized to the z.enum(...) call that validates
OAuthProviderRecord keys.

In `@packages/core/src/api/refreshUserInfo.ts`:
- Around line 75-77: The expiresIn calculation in refreshUserInfo is mixing
units because tokens.expiresAt is in Unix seconds while Date.now() is in
milliseconds, causing incorrect zero values for future expiries. Update the
subtraction logic in refreshUserInfo to compare expiresAt against Unix seconds
by using Math.floor(Date.now() / 1000), and keep the existing
Math.max/Math.floor behavior so custom userInfo handlers receive a correct
expires_in value.
- Around line 103-108: Handle the null-return shape from createStandardSession
in refreshUserInfo: when userClaims.sub is missing, it returns an object with
session set to null and headers, but the current assignment stores the whole
object in session. Update refreshUserInfo to destructure the
createStandardSession result and use only its session value in the response
body, while still preserving the returned headers as needed, so the response
stays { session: null, success: true } in that edge case.

In `@packages/core/src/client/client.ts`:
- Around line 339-346: The JSDoc example in the refreshUserInfo documentation
shows the wrong user identifier field; update the example session object to use
sub instead of id so it matches the actual AuthClient session shape and related
expectations. Keep the rest of the example unchanged and ensure the `@example`
near refreshUserInfo reflects the same identifiers used by the client API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a36ed73e-0654-41a6-a196-85aded39f3c3

📥 Commits

Reviewing files that changed from the base of the PR and between d0578c5 and dd8a24b.

📒 Files selected for processing (12)
  • packages/core/CHANGELOG.md
  • packages/core/src/actions/callback/userinfo.ts
  • packages/core/src/actions/user/refresh.ts
  • packages/core/src/api/createApi.ts
  • packages/core/src/api/refreshUserInfo.ts
  • packages/core/src/client/client.ts
  • packages/core/src/createAuth.ts
  • packages/core/src/router/rate-limiter.ts
  • packages/core/src/shared/errors.ts
  • packages/core/src/shared/utils.ts
  • packages/core/test/actions/user/refresh.test.ts
  • packages/core/test/api/refreshUserInfo.test.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/core/CHANGELOG.md
  • packages/core/src/actions/callback/userinfo.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/core/src/api/createApi.ts
  • packages/core/src/shared/errors.ts
  • packages/core/src/router/rate-limiter.ts
  • packages/core/src/shared/utils.ts
  • packages/core/test/api/refreshUserInfo.test.ts

Comment thread packages/core/src/actions/user/refresh.ts
Comment thread packages/core/src/api/refreshUserInfo.ts
Comment thread packages/core/src/api/refreshUserInfo.ts
Comment thread packages/core/src/client/client.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant