Compare commits

..

1 Commits

Author SHA1 Message Date
Balázs Orbán
430aa48557 chore(release): bump version 2022-04-14 09:07:07 +00:00
56 changed files with 195 additions and 205 deletions

View File

@@ -30,7 +30,7 @@
"type": "module",
"dependencies": {
"cookie": "0.4.1",
"next-auth": "^4.3.2"
"next-auth": "^4.2.1"
},
"prettier": {
"semi": false,

View File

@@ -1232,10 +1232,10 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
next-auth@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.2.tgz#eb4976511fb19766d0397bd4de45eee87c5c1998"
integrity sha512-yj9HN9p81Fg3dkrq4Y0FxjfgupiABac7o+ve47j5GPLjo1qE2FFX1pr7g7mwQ1HDUCoGhLmgBpFBR8+pdWgFfQ==
next-auth@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.2.1.tgz#042e4858d9f67b4f702d3a55bae0d2f04db3cac3"
integrity sha512-XDtt7nqevkNf4EJ2zKAKkI+MFsURf11kx11vPwxrBYA1MHeqWwaWbGOUOI2ekNTvfAg4nTEJJUH3LV2cLrH3Tg==
dependencies:
"@babel/runtime" "^7.16.3"
"@panva/hkdf" "^1.0.1"

View File

@@ -89,7 +89,7 @@ The default redirect callback looks like this:
callbacks: {
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
if (url.startsWith("/")) return `${baseUrl}${url}`
if (url.startsWith("/")) return new URL(url, baseUrl).toString()
// Allows callback URLs on the same origin
else if (new URL(url).origin === baseUrl) return url
return baseUrl

View File

@@ -285,6 +285,7 @@ events: {
async updateUser(message) { /* user updated - e.g. their email was verified */ },
async linkAccount(message) { /* account (e.g. Twitter) linked to a user */ },
async session(message) { /* session is active */ },
async error(message) { /* error in authentication flow */ }
}
```

View File

@@ -51,7 +51,7 @@ The following errors are passed as error query parameters to the default or over
- **SessionRequired**: The content of this page requires you to be signed in at all times. See [useSession](/getting-started/client#require-session) for configuration.
- **Default**: Catch all, will apply, if none of the above matched
Example: `/auth/signin?error=Default`
Example: `/auth/error?error=Default`
## Theming
@@ -90,15 +90,23 @@ export default function SignIn({ providers }) {
)
}
// This is the recommended way for Next.js 9.3 or newer
export async function getServerSideProps(context) {
const providers = await getProviders()
return {
props: { providers },
}
}
```
There is another, more fully styled example signin page available [here](https://github.com/ndom91/next-auth-example-sign-in-page).
/*
// If older than Next.js 9.3
SignIn.getInitialProps = async () => {
return {
providers: await getProviders()
}
}
*/
```
### Email Sign in
@@ -120,12 +128,22 @@ export default function SignIn({ csrfToken }) {
)
}
// This is the recommended way for Next.js 9.3 or newer
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken(context)
return {
props: { csrfToken },
}
}
/*
// If older than Next.js 9.3
SignIn.getInitialProps = async (context) => {
return {
csrfToken: await getCsrfToken(context)
}
}
*/
```
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:
@@ -158,6 +176,7 @@ export default function SignIn({ csrfToken }) {
)
}
// This is the recommended way for Next.js 9.3 or newer
export async function getServerSideProps(context) {
return {
props: {
@@ -165,6 +184,15 @@ export async function getServerSideProps(context) {
},
}
}
/*
// If older than Next.js 9.3
SignIn.getInitialProps = async (context) => {
return {
csrfToken: await getCsrfToken(context)
}
}
*/
```
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:

View File

@@ -111,13 +111,9 @@ This error occurs when there was no `authorize()` handler defined on the credent
#### PKCE_ERROR
The provider you tried to use failed when setting [PKCE or Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636#section-4).
The provider you tried to use failed when setting [PKCE or Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636#section-4.2).
The `code_verifier` is saved in a cookie called (by default) `__Secure-next-auth.pkce.code_verifier` which expires after 15 minutes.
Check if `cookies.pkceCodeVerifier` is configured correctly.
The default `code_challenge_method` is `"S256"`. This is currently not configurable to `"plain"`, [as per RFC7636](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2):
> If the client is capable of using "S256", it MUST use "S256", as
S256" is Mandatory To Implement (MTI) on the server.
Check if `cookies.pkceCodeVerifier` is configured correctly. The default `code_challenge_method` is `"S256"`. This is currently not configurable to `"plain"`, as it is not recommended, and in most cases, it is only supported for backward compatibility.
---

View File

@@ -23,7 +23,7 @@ The **Credentials Provider** comes with a set of default options:
You can override any of the options to suit your own use case.
## Example - Username / Password
## Example
The Credentials provider is specified like other providers, except that you need to define a handler for `authorize()` that accepts credentials submitted via HTTP POST as input and returns either:
@@ -73,19 +73,9 @@ providers: [
See the [callbacks documentation](/configuration/callbacks) for more information on how to interact with the token.
## Example - Web3 / Signin With Ethereum
The credentials provider can also be used to integrate with a service like [Sign-in With Ethereum](https://login.xyz).
For more information, check out the links below:
- [Tutorial](https://docs.login.xyz/integrations/nextauth.js)
- [Example App Repo](https://github.com/spruceid/siwe-next-auth-example).
- [Example App Demo](https://siwe-next-auth-example2.vercel.app/).
## Multiple providers
### Example
### Example code
You can specify more than one credentials provider by specifying a unique `id` for each one.

View File

@@ -15,7 +15,7 @@ https://discord.com/developers/applications
The **Discord Provider** comes with a set of default options:
- [Discord Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/discord.ts)
- [Discord Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/discord.js)
You can override any of the options to suit your own use case.

View File

@@ -37,5 +37,5 @@ providers: [
```
:::note
`issuer` should include the realm  e.g. `https://my-keycloak-domain.com/realms/My_Realm`
`issuer` should include the realm  e.g. `https://my-keycloak-domain.com/auth/realms/My_Realm`
:::

View File

@@ -94,10 +94,20 @@ export default function SignIn({ providers }) {
)
}
// This is the recommended way for Next.js 9.3 or newer
export async function getServerSideProps(context) {
const providers = await getProviders()
return {
props: { providers },
}
}
/*
// If older than Next.js 9.3
SignIn.getInitialProps = async () => {
return {
providers: await getProviders()
}
}
*/
```

View File

@@ -44,7 +44,6 @@ title: Tutorials and Explainers
#### [How to authenticate Next.js Apps with Sign-In With Ethereum (SIWE) & NextAuth.js](https://docs.login.xyz/integrations/nextauth.js) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
- Learn how to use Sign-In With Ethereum to authenticate your users with their existing Ethereum wallets - identifiers they personally control.
- Example application: [spruceid/siwe-next-auth-example](https://github.com/spruceid/siwe-next-auth-example)
## Fullstack

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/upstash-redis-adapter",
"version": "3.0.0",
"version": "2.0.0",
"description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -44,4 +44,4 @@
"jest": {
"preset": "adapter-test/jest"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "4.3.4",
"version": "4.3.2",
"description": "Authentication for Next.js",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/next-auth.git",
@@ -76,8 +76,8 @@
},
"peerDependencies": {
"nodemailer": "^6.6.5",
"react": "^17.0.2 || ^18",
"react-dom": "^17.0.2 || ^18"
"react": "^17.0.2 || ^18.0.0-0",
"react-dom": "^17.0.2 || ^18.0.0-0"
},
"peerDependenciesMeta": {
"nodemailer": {
@@ -132,4 +132,4 @@
"**/tests",
"**/__tests__"
]
}
}

View File

@@ -45,7 +45,7 @@ test("returns the Cross Site Request Forgery Token (CSRF Token) required to make
test("when there's no CSRF token returned, it'll reflect that", async () => {
server.use(
rest.get("*/api/auth/csrf", (req, res, ctx) =>
rest.get("/api/auth/csrf", (req, res, ctx) =>
res(
ctx.status(200),
ctx.json({
@@ -67,7 +67,7 @@ test("when there's no CSRF token returned, it'll reflect that", async () => {
test("when the fetch fails it'll throw a client fetch error", async () => {
server.use(
rest.get("*/api/auth/csrf", (req, res, ctx) =>
rest.get("/api/auth/csrf", (req, res, ctx) =>
res(ctx.status(500), ctx.text("some error happened"))
)
)

View File

@@ -65,26 +65,28 @@ export const mockSignOutResponse = {
}
export const server = setupServer(
rest.post("*/api/auth/signout", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signout", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockSignOutResponse))
),
rest.get("*/api/auth/session", (req, res, ctx) =>
rest.get("http://localhost/api/auth/session", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockSession))
),
rest.get("*/api/auth/csrf", (req, res, ctx) =>
rest.get("http://localhost/api/auth/csrf", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockCSRFToken))
),
rest.get("*/api/auth/providers", (req, res, ctx) =>
rest.get("http://localhost/api/auth/providers", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockProviders))
),
rest.post("*/api/auth/signin/github", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signin/github", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockGithubResponse))
),
rest.post("*/api/auth/callback/credentials", (req, res, ctx) =>
rest.post("http://localhost/api/auth/callback/credentials", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockCredentialsResponse))
),
rest.post("*/api/auth/signin/email", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signin/email", (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockEmailResponse))
),
rest.post("*/api/auth/_log", (req, res, ctx) => res(ctx.status(200)))
rest.post("http://localhost/api/auth/_log", (req, res, ctx) =>
res(ctx.status(200))
)
)

View File

@@ -45,7 +45,7 @@ test("when called it'll return the currently configured providers for sign in",
test("when failing to fetch the providers, it'll log the error", async () => {
server.use(
rest.get("*/api/auth/providers", (req, res, ctx) =>
rest.get("/api/auth/providers", (req, res, ctx) =>
res(ctx.status(500), ctx.text("some error happened"))
)
)

View File

@@ -61,7 +61,7 @@ test("if it can fetch the session, it should store it in `localStorage`", async
test("if there's an error fetching the session, it should log it", async () => {
server.use(
rest.get("*/api/auth/session", (req, res, ctx) => {
rest.get("/api/auth/session", (req, res, ctx) => {
return res(ctx.status(500), ctx.body("Server error"))
})
)

View File

@@ -195,7 +195,7 @@ test("if callback URL contains a hash we force a window reload when re-directing
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"
server.use(
rest.post("*/api/auth/signin/email", (req, res, ctx) => {
rest.post("http://localhost/api/auth/signin/email", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
@@ -222,7 +222,7 @@ test("params are propagated to the signin URL when supplied", async () => {
const authParams = "foo=bar&bar=foo"
server.use(
rest.post("*/auth/signin/github", (req, res, ctx) => {
rest.post("http://localhost/api/auth/signin/github", (req, res, ctx) => {
matchedParams = req.url.search
return res(ctx.status(200), ctx.json(mockGithubResponse))
})
@@ -241,7 +241,7 @@ test("when it fails to fetch the providers, it redirected back to signin page",
const errorMsg = "Error when retrieving providers"
server.use(
rest.get("*/api/auth/providers", (req, res, ctx) =>
rest.get("http://localhost/api/auth/providers", (req, res, ctx) =>
res(ctx.status(500), ctx.json(errorMsg))
)
)

View File

@@ -37,7 +37,7 @@ const callbackUrl = "https://redirects/to"
test("by default it redirects to the current URL if the server did not provide one", async () => {
server.use(
rest.post("*/api/auth/signout", (req, res, ctx) =>
rest.post("http://localhost/api/auth/signout", (req, res, ctx) =>
res(ctx.status(200), ctx.json({ ...mockSignOutResponse, url: undefined }))
)
)
@@ -61,7 +61,7 @@ test("it redirects to the URL allowed by the server", async () => {
})
})
test.skip("if url contains a hash during redirection a page reload happens", async () => {
test("if url contains a hash during redirection a page reload happens", async () => {
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"
server.use(

View File

@@ -120,7 +120,7 @@ export class SessionStore {
option: CookieOption,
req: {
cookies?: Record<string, string>
headers?: Headers | IncomingHttpHeaders | Record<string, string>
headers?: Record<string, string> | IncomingHttpHeaders
},
logger: LoggerInstance | Console
) {

View File

@@ -5,7 +5,7 @@ export const defaultCallbacks: CallbacksOptions = {
return true
},
redirect({ url, baseUrl }) {
if (url.startsWith("/")) return `${baseUrl}${url}`
if (url.startsWith("/")) return new URL(url, baseUrl).toString()
else if (new URL(url).origin === baseUrl) return url
return baseUrl
},

View File

@@ -123,11 +123,10 @@ export default function SigninPage(props: SignInServerPageParams) {
<input
id={`input-email-for-${provider.id}-provider`}
autoFocus
type="email"
type="text"
name="email"
value={email}
placeholder="email@example.com"
required
/>
<button type="submit">Sign in with {provider.name}</button>
</form>

View File

@@ -47,6 +47,7 @@ export interface NextAuthOptions {
*/
session?: Partial<SessionOptions>
/**
* JSON Web Tokens can be used for session tokens if enabled with the `session: { jwt: true }` option.
* JSON Web Tokens are enabled by default if you have not specified a database.
* By default JSON Web Tokens are signed (JWS) but not encrypted (JWE),
* as JWT encryption adds additional overhead and comes with some caveats.

View File

@@ -3,7 +3,6 @@ import hkdf from "@panva/hkdf"
import { v4 as uuid } from "uuid"
import { SessionStore } from "../core/lib/cookie"
import type { NextApiRequest } from "next"
import type { NextRequest } from "next/server"
import type { JWT, JWTDecodeParams, JWTEncodeParams, JWTOptions } from "./types"
import type { LoggerInstance } from ".."
@@ -38,7 +37,7 @@ export async function decode(params: JWTDecodeParams): Promise<JWT | null> {
export interface GetTokenParams<R extends boolean = false> {
/** The request containing the JWT either in the cookies or in the `Authorization` header. */
req: NextRequest | NextApiRequest
req: NextApiRequest | Pick<NextApiRequest, "cookies" | "headers">
/**
* Use secure prefix for cookie name, unless URL in `NEXTAUTH_URL` is http://
* or not set (e.g. development or test instance) case use unprefixed name
@@ -91,13 +90,8 @@ export async function getToken<R extends boolean = false>(
let token = sessionStore.value
const authorizationHeader =
req.headers instanceof Headers
? req.headers.get("authorization")
: req.headers.authorization
if (!token && authorizationHeader?.split(" ")[0] === "Bearer") {
const urlEncodedToken = authorizationHeader.split(" ")[1]
if (!token && req.headers.authorization?.split(" ")[0] === "Bearer") {
const urlEncodedToken = req.headers.authorization.split(" ")[1]
token = decodeURIComponent(urlEncodedToken)
}

View File

@@ -81,7 +81,7 @@ async function handleMiddleware(
return NextResponse.redirect(errorUrl)
}
const token = await getToken({ req })
const token = await getToken({ req: req as any })
const isAuthorized =
(await options?.callbacks?.authorized?.({ req, token })) ?? !!token

View File

@@ -134,7 +134,8 @@ export interface CampusUser {
created_at: string
updated_at: string | null
}
export interface FortyTwoProfile extends UserData, Record<string, any> {
export interface FortyTwoProfile extends UserData {
groups: Array<{ id: string; name: string }>
cursus_users: CursusUser[]
projects_users: ProjectUser[]
@@ -152,9 +153,9 @@ export interface FortyTwoProfile extends UserData, Record<string, any> {
user: any | null
}
export default function FortyTwo<P extends FortyTwoProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function FortyTwo<
P extends Record<string, any> = FortyTwoProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "42-school",
name: "42 School",

View File

@@ -5,7 +5,7 @@ import { OAuthConfig, OAuthUserConfig } from "."
* [Retrieve the User's Information from Apple ID Servers
](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple#3383773)
*/
export interface AppleProfile extends Record<string, any> {
export interface AppleProfile {
/**
* The issuer registered claim identifies the principal that issued the identity token.
* Since Apple generates the token, the value is `https://appleid.apple.com`.
@@ -87,7 +87,7 @@ export interface AppleProfile extends Record<string, any> {
auth_time: number
}
export default function Apple<P extends AppleProfile>(
export default function Apple<P extends Record<string, any> = AppleProfile>(
options: Omit<OAuthUserConfig<P>, "clientSecret"> & {
/**
* Apple requires the client secret to be a JWT. You can generate one using the following script:

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
interface AtlassianProfile extends Record<string, any> {
interface AtlassianProfile {
account_id: string
name: string
email: string

View File

@@ -1,13 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface Auth0Profile extends Record<string, any> {
export interface Auth0Profile {
sub: string
nickname: string
email: string
picture: string
}
export default function Auth0<P extends Auth0Profile>(
export default function Auth0<P extends Record<string, any> = Auth0Profile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,29 +1,29 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface AuthentikProfile extends Record<string, any> {
iss: string
sub: string
aud: string
exp: number
iat: number
auth_time: number
acr: string
c_hash: string
nonce: string
at_hash: string
email: string
email_verified: boolean
name: string
given_name: string
family_name: string
preferred_username: string
nickname: string
export interface AuthentikProfile {
iss: string,
sub: string,
aud: string,
exp: number,
iat: number,
auth_time: number,
acr: string,
c_hash: string,
nonce: string,
at_hash: string,
email: string,
email_verified: boolean,
name: string,
given_name: string,
family_name: string,
preferred_username: string,
nickname: string,
groups: string[]
}
export default function Authentik<P extends AuthentikProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function Authentik<
P extends Record<string, any> = AuthentikProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "authentik",
name: "Authentik",

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface AzureB2CProfile extends Record<string, any> {
export interface AzureB2CProfile {
exp: number
nbf: number
ver: string
@@ -17,7 +17,9 @@ export interface AzureB2CProfile extends Record<string, any> {
tfp: string
}
export default function AzureADB2C<P extends AzureB2CProfile>(
export default function AzureADB2C<
P extends Record<string, any> = AzureB2CProfile
>(
options: OAuthUserConfig<P> & {
primaryUserFlow: string
tenantId: string

View File

@@ -1,13 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface AzureADProfile extends Record<string, any> {
export interface AzureADProfile {
sub: string
nicname: string
email: string
picture: string
}
export default function AzureAD<P extends AzureADProfile>(
export default function AzureAD<P extends Record<string, any> = AzureADProfile>(
options: OAuthUserConfig<P> & {
/**
* https://docs.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0#examples

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface BattleNetProfile extends Record<string, any> {
export interface BattleNetProfile {
sub: string
battle_tag: string
}
@@ -10,9 +10,9 @@ export type BattleNetIssuer =
| "https://www.battlenet.com.cn/oauth"
| `https://${"us" | "eu" | "kr" | "tw"}.battle.net/oauth`
export default function BattleNet<P extends BattleNetProfile>(
options: OAuthUserConfig<P> & { issuer: BattleNetIssuer }
): OAuthConfig<P> {
export default function BattleNet<
P extends Record<string, any> = BattleNetProfile
>(options: OAuthUserConfig<P> & { issuer: BattleNetIssuer }): OAuthConfig<P> {
return {
id: "battlenet",
name: "Battle.net",

View File

@@ -1,15 +1,15 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface BoxyHQSAMLProfile extends Record<string, any> {
export interface BoxyHQSAMLProfile {
id: string
email: string
firstName?: string
lastName?: string
}
export default function SAMLJackson<P extends BoxyHQSAMLProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function SAMLJackson<
P extends Record<string, any> = BoxyHQSAMLProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "boxyhq-saml",
name: "BoxyHQ SAML",
@@ -34,4 +34,4 @@ export default function SAMLJackson<P extends BoxyHQSAMLProfile>(
},
options,
}
}
}

View File

@@ -1,13 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface CognitoProfile extends Record<string, any> {
export interface CognitoProfile {
sub: string
name: string
email: string
picture: string
}
export default function Cognito<P extends CognitoProfile>(
export default function Cognito<P extends Record<string, any> = CognitoProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,26 +1,5 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface DiscordProfile extends Record<string, any> {
accent_color: number
avatar: string
banner: string
banner_color: string
discriminator: string
email: string
flags: number
id: string
image_url: string
locale: string
mfa_enabled: boolean
premium_type: number
public_flags: number
username: string
verified: boolean
}
export default function Discord<P extends DiscordProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
/** @type {import(".").OAuthProvider} */
export default function Discord(options) {
return {
id: "discord",
name: "Discord",

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface EVEOnlineProfile extends Record<string, any> {
export interface EVEOnlineProfile {
CharacterID: number
CharacterName: string
ExpiresOn: string
@@ -10,9 +10,9 @@ export interface EVEOnlineProfile extends Record<string, any> {
IntellectualProperty: string
}
export default function EVEOnline<P extends EVEOnlineProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function EVEOnline<
P extends Record<string, any> = EVEOnlineProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "eveonline",
name: "EVE Online",
@@ -27,7 +27,7 @@ export default function EVEOnline<P extends EVEOnlineProfile>(
idToken: true,
profile(profile) {
return {
id: String(profile.CharacterID),
id: profile.CharacterID,
name: profile.CharacterName,
email: null,
image: `https://image.eveonline.com/Character/${profile.CharacterID}_128.jpg`,

View File

@@ -1,20 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
interface FacebookPictureData {
url: string
}
interface FacebookPicture {
data: FacebookPictureData
}
export interface FacebookProfile extends Record<string, any> {
export interface FacebookProfile {
id: string
picture: FacebookPicture
picture: { data: { url: string } }
}
export default function Facebook<P extends FacebookProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function Facebook<
P extends Record<string, any> = FacebookProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "facebook",
name: "Facebook",

View File

@@ -3,7 +3,7 @@ import { OAuthConfig, OAuthUserConfig } from "./oauth"
/** This is the default openid signature returned from FusionAuth
* it can be customized using [lambda functions](https://fusionauth.io/docs/v1/tech/lambdas)
*/
export interface FusionAuthProfile extends Record<string, any> {
export interface FusionAuthProfile {
aud: string
exp: number
iat: number
@@ -20,7 +20,9 @@ export interface FusionAuthProfile extends Record<string, any> {
sid: string
}
export default function FusionAuth<P extends FusionAuthProfile>(
export default function FusionAuth<
P extends Record<string, any> = FusionAuthProfile
>(
// tenantId only needed if there is more than one tenant configured on the server
options: OAuthUserConfig<P> & { tenantId?: string }
): OAuthConfig<P> {

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface GoogleProfile extends Record<string, any> {
export interface GoogleProfile {
aud: string
azp: string
email: string
@@ -18,7 +18,7 @@ export interface GoogleProfile extends Record<string, any> {
sub: string
}
export default function Google<P extends GoogleProfile>(
export default function Google<P extends Record<string, any> = GoogleProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -19,7 +19,7 @@ export type AgeRange =
* https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info
* type from : https://gist.github.com/ziponia/cdce1ebd88f979b2a6f3f53416b56a77
*/
export interface KakaoProfile extends Record<string, any> {
export interface KakaoProfile {
id: number
has_signed_up?: boolean
connected_at?: DateTime
@@ -66,7 +66,7 @@ export interface KakaoProfile extends Record<string, any> {
}
}
export default function Kakao<P extends KakaoProfile>(
export default function Kakao<P extends Record<string, any> = KakaoProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {
@@ -81,10 +81,10 @@ export default function Kakao<P extends KakaoProfile>(
},
profile(profile) {
return {
id: String(profile.id),
name: profile.kakao_account?.profile?.nickname,
id: profile.id,
name: profile.kakao_account?.profile.nickname,
email: profile.kakao_account?.email,
image: profile.kakao_account?.profile?.profile_image_url,
image: profile.kakao_account?.profile.profile_image_url,
}
},
options,

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface KeycloakProfile extends Record<string, any> {
export interface KeycloakProfile {
exp: number
iat: number
auth_time: number
@@ -24,9 +24,9 @@ export interface KeycloakProfile extends Record<string, any> {
user: any
}
export default function Keycloak<P extends KeycloakProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function Keycloak<
P extends Record<string, any> = KeycloakProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "keycloak",
name: "Keycloak",

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface LineProfile extends Record<string, any> {
export interface LineProfile {
iss: string
sub: string
aud: string
@@ -12,7 +12,7 @@ export interface LineProfile extends Record<string, any> {
user: any
}
export default function LINE<P extends LineProfile>(
export default function LINE<P extends Record<string, any> = LineProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -8,7 +8,7 @@ interface Element {
identifiers?: Identifier[]
}
export interface LinkedInProfile extends Record<string, any> {
export interface LinkedInProfile {
id: string
localizedFirstName: string
localizedLastName: string
@@ -19,9 +19,9 @@ export interface LinkedInProfile extends Record<string, any> {
}
}
export default function LinkedIn<P extends LinkedInProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function LinkedIn<
P extends Record<string, any> = LinkedInProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "linkedin",
name: "LinkedIn",

View File

@@ -1,7 +1,7 @@
import type { OAuthConfig, OAuthUserConfig } from "."
/** https://developers.naver.com/docs/login/profile/profile.md */
export interface NaverProfile extends Record<string, any> {
export interface NaverProfile {
resultcode: string
message: string
response: {
@@ -18,7 +18,7 @@ export interface NaverProfile extends Record<string, any> {
}
}
export default function Naver<P extends NaverProfile>(
export default function Naver<P extends Record<string, any> = NaverProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface OktaProfile extends Record<string, any> {
export interface OktaProfile {
iss: string
ver: string
sub: string
@@ -34,7 +34,7 @@ export interface OktaProfile extends Record<string, any> {
c_hash: string
}
export default function Okta<P extends OktaProfile>(
export default function Okta<P extends Record<string, any> = OktaProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -16,7 +16,7 @@ export interface OsuUserCompact {
username: string
}
export interface OsuProfile extends OsuUserCompact, Record<string, any> {
export interface OsuProfile extends OsuUserCompact {
discord: string | null
has_supported: boolean
interests: string | null
@@ -49,7 +49,7 @@ export interface OsuProfile extends OsuUserCompact, Record<string, any> {
is_restricted: boolean
}
export default function Osu<P extends OsuProfile>(
export default function Osu<P extends Record<string, any> = OsuProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,13 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface PatreonProfile extends Record<string, any> {
export interface PatreonProfile {
sub: string
nickname: string
email: string
picture: string
}
export default function Patreon<P extends PatreonProfile>(
export default function Patreon<P extends Record<string, any> = PatreonProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface PipedriveProfile extends Record<string, any> {
export interface PipedriveProfile {
success: boolean
data: {
id: number
@@ -35,9 +35,9 @@ export interface PipedriveProfile extends Record<string, any> {
}
}
export default function Pipedrive<P extends PipedriveProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function Pipedrive<
P extends Record<string, any> = PipedriveProfile
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "pipedrive",
name: "Pipedrive",
@@ -48,7 +48,7 @@ export default function Pipedrive<P extends PipedriveProfile>(
userinfo: "https://api.pipedrive.com/users/me",
profile: ({ data: profile }) => {
return {
id: String(profile.id),
id: profile.id,
name: profile.name,
email: profile.email,
image: profile.icon_url,

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface SlackProfile extends Record<string, any> {
export interface SlackProfile {
ok: boolean
sub: string
"https://slack.com/user_id": string
@@ -32,7 +32,7 @@ export interface SlackProfile extends Record<string, any> {
"https://slack.com/team_image_default": boolean
}
export default function Slack<P extends SlackProfile>(
export default function Slack<P extends Record<string, any> = SlackProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -4,13 +4,13 @@ export interface SpotifyImage {
url: string
}
export interface SpotifyProfile extends Record<string, any> {
export interface SpotifyProfile {
id: string
display_name: string
email: string
images: SpotifyImage[]
}
export default function Spotify<P extends SpotifyProfile>(
export default function Spotify<P extends Record<string, any> = SpotifyProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface TraktUser extends Record<string, any> {
export interface TraktUser {
username: string
private: boolean
name: string
@@ -15,9 +15,9 @@ export interface TraktUser extends Record<string, any> {
images: { avatar: { full: string } }
}
export default function Trakt<P extends TraktUser>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
export default function Trakt<
P extends Record<string, any> = TraktUser
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
return {
id: "trakt",
name: "Trakt",

View File

@@ -1,13 +1,13 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface TwitchProfile extends Record<string, any> {
export interface TwitchProfile {
sub: string
preferred_username: string
email: string
picture: string
}
export default function Twitch<P extends TwitchProfile>(
export default function Twitch<P extends Record<string, any> = TwitchProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface WorkOSProfile extends Record<string, any> {
export interface WorkOSProfile {
object: string
id: string
organization_id: string
@@ -15,11 +15,10 @@ export interface WorkOSProfile extends Record<string, any> {
email: string
lastName: string
firstName: string
picture: string
}
}
export default function WorkOS<P extends WorkOSProfile>(
export default function WorkOS<P extends Record<string, any> = WorkOSProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
const { issuer = "https://api.workos.com/" } = options

View File

@@ -1,6 +1,6 @@
import type { OAuthConfig, OAuthUserConfig } from "."
export interface ZoomProfile extends Record<string, any> {
export interface ZoomProfile {
id: string
first_name: string
last_name: string
@@ -29,7 +29,7 @@ export interface ZoomProfile extends Record<string, any> {
status: string
}
export default function Zoom<P extends ZoomProfile>(
export default function Zoom<P extends Record<string, any> = ZoomProfile>(
options: OAuthUserConfig<P>
): OAuthConfig<P> {
return {

View File

@@ -359,12 +359,6 @@ export function SessionProvider(props: SessionProviderProps) {
}
__NEXTAUTH._getSession()
return () => {
__NEXTAUTH._lastSync = 0
__NEXTAUTH._session = undefined
__NEXTAUTH._getSession = () => {}
}
}, [])
React.useEffect(() => {