[OAuthEndpointType],
issuer?: string
diff --git a/packages/core/src/lib/routes/callback.ts b/packages/core/src/lib/routes/callback.ts
index 4b0fead9fb..dba511ead9 100644
--- a/packages/core/src/lib/routes/callback.ts
+++ b/packages/core/src/lib/routes/callback.ts
@@ -68,14 +68,18 @@ export async function callback(params: {
logger.debug("authorization result", authorizationResult)
- const { profile, account, OAuthProfile } = authorizationResult
+ const {
+ user: userFromProvider,
+ account,
+ OAuthProfile,
+ } = authorizationResult
// If we don't have a profile object then either something went wrong
// or the user cancelled signing in. We don't know which, so we just
// direct the user to the signin page for now. We could do something
// else in future.
// TODO: Handle user cancelling signin
- if (!profile || !account || !OAuthProfile) {
+ if (!userFromProvider || !account || !OAuthProfile) {
return { redirect: `${url}/signin`, cookies }
}
@@ -83,7 +87,7 @@ export async function callback(params: {
// Attempt to get Profile from OAuth provider details before invoking
// signIn callback - but if no user object is returned, that is fine
// (that just means it's a new user signing in for the first time).
- let userOrProfile = profile
+ let userByAccountOrFromProvider
if (adapter) {
const { getUserByAccount } = adapter
const userByAccount = await getUserByAccount({
@@ -91,11 +95,15 @@ export async function callback(params: {
provider: provider.id,
})
- if (userByAccount) userOrProfile = userByAccount
+ if (userByAccount) userByAccountOrFromProvider = userByAccount
}
const unauthorizedOrError = await handleAuthorized(
- { user: userOrProfile, account, profile: OAuthProfile },
+ {
+ user: userByAccountOrFromProvider,
+ account,
+ profile: OAuthProfile,
+ },
options
)
@@ -104,7 +112,7 @@ export async function callback(params: {
// Sign user in
const { user, session, isNewUser } = await handleLogin(
sessionStore.value,
- profile,
+ userFromProvider,
account,
options
)
@@ -152,7 +160,7 @@ export async function callback(params: {
})
}
- await events.signIn?.({ user, account, profile, isNewUser })
+ await events.signIn?.({ user, account, profile: OAuthProfile, isNewUser })
// Handle first logins on new accounts
// e.g. option to send users to a new account landing page on initial login
diff --git a/packages/core/src/providers/oauth.ts b/packages/core/src/providers/oauth.ts
index 8069abef90..0f13eae610 100644
--- a/packages/core/src/providers/oauth.ts
+++ b/packages/core/src/providers/oauth.ts
@@ -52,7 +52,10 @@ interface AdvancedEndpointHandler {
conform?: (response: Response) => Awaitable
}
-/** Either an URL (containing all the parameters) or an object with more granular control. */
+/**
+ * Either an URL (containing all the parameters) or an object with more granular control.
+ * @internal
+ */
export type EndpointHandler<
P extends UrlParams,
C = any,
@@ -92,6 +95,8 @@ export type ProfileCallback = (
tokens: TokenSet
) => Awaitable
+export type AccountCallback = (account: TokenSet) => TokenSet
+
export interface OAuthProviderButtonStyles {
logo: string
logoDark: string
@@ -138,13 +143,25 @@ export interface OAuth2Config
userinfo?: string | UserinfoEndpointHandler
type: "oauth"
/**
- * Receives the profile object returned by the OAuth provider, and returns the user object.
- * This will be used to create the user in the database.
+ * Receives the full {@link Profile} returned by the OAuth provider, and returns a subset.
+ * It is used to create the user in the database.
+ *
* Defaults to: `id`, `email`, `name`, `image`
*
- * [Documentation](https://authjs.dev/reference/adapters/models#user)
+ * @see [Database Adapter: User model](https://authjs.dev/reference/adapters#user)
*/
profile?: ProfileCallback
+ /**
+ * Receives the full {@link TokenSet} returned by the OAuth provider, and returns a subset.
+ * It is used to create the account associated with a user in the database.
+ *
+ * Defaults to: `access_token` and `id_token`
+ *
+ * @see [Database Adapter: Account model](https://authjs.dev/reference/adapters#account)
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
+ * @see https://www.ietf.org/rfc/rfc6749.html#section-5.1
+ */
+ account?: AccountCallback
/**
* The CSRF protection performed on the callback endpoint.
* @default ["pkce"]
@@ -190,7 +207,11 @@ export interface OAuth2Config
options?: OAuthUserConfig
}
-/** TODO: Document */
+/**
+ * Extension of the {@link OAuth2Config}.
+ *
+ * @see https://openid.net/specs/openid-connect-core-1_0.html
+ */
export interface OIDCConfig
extends Omit, "type" | "checks"> {
type: "oidc"
@@ -204,6 +225,7 @@ export type OAuthEndpointType = "authorization" | "token" | "userinfo"
/**
* We parsed `authorization`, `token` and `userinfo`
* to always contain a valid `URL`, with the params
+ * @internal
*/
export type OAuthConfigInternal = Omit<
OAuthConfig,
@@ -229,7 +251,10 @@ export type OAuthConfigInternal = Omit<
*
*/
redirectProxyUrl?: OAuth2Config["redirectProxyUrl"]
-} & Pick>, "clientId" | "checks" | "profile">
+} & Pick<
+ Required>,
+ "clientId" | "checks" | "profile" | "account"
+ >
export type OIDCConfigInternal = OAuthConfigInternal & {
checks: OIDCConfig["checks"]
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index 8d5a5b4309..5d154be87b 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -116,16 +116,58 @@ export interface Account extends Partial {
providerAccountId: string
/** Provider's type for this account */
type: ProviderType
- /** id of the user this account belongs to */
+ /**
+ * id of the user this account belongs to
+ *
+ * @see https://authjs.dev/reference/adapters#user
+ */
userId?: string
+ /**
+ * Calculated value based on {@link OAuth2TokenEndpointResponse.expires_in}.
+ *
+ * It is the absolute timestamp (in seconds) when the {@link OAuth2TokenEndpointResponse.access_token} expires.
+ *
+ * This value can be used for implementing token rotation together with {@link OAuth2TokenEndpointResponse.refresh_token}.
+ *
+ * @see https://authjs.dev/guides/basics/refresh-token-rotation#database-strategy
+ * @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
+ */
+ expires_at?: number
}
-/** The OAuth profile returned from your provider */
+/**
+ * The user info returned from your OAuth provider.
+ *
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
+ */
export interface Profile {
- sub?: string | null
- name?: string | null
- email?: string | null
- image?: string | null
+ sub: string
+ name?: string
+ given_name?: string
+ family_name?: string
+ middle_name?: string
+ nickname?: string
+ preferred_username?: string
+ profile?: string
+ picture?: string
+ website?: string
+ email?: string
+ email_verified?: boolean
+ gender?: string
+ birthdate?: string
+ zoneinfo?: string
+ locale?: string
+ phone_number?: string
+ updated_at?: number
+ address?: {
+ formatted?: string
+ street_address?: string
+ locality?: string
+ region?: string
+ postal_code?: string
+ country?: string
+ }
+ [claim: string]: unknown
}
/** [Documentation](https://authjs.dev/guides/basics/callbacks) */