mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
15 Commits
next-auth@
...
next-auth@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6903d3e85 | ||
|
|
a74d215745 | ||
|
|
18174fae36 | ||
|
|
d4fb7af6f5 | ||
|
|
bc15e2866e | ||
|
|
aee5ec2e4f | ||
|
|
f0ed23acf6 | ||
|
|
fb4bbc3b08 | ||
|
|
4c832f855e | ||
|
|
e3ace6e649 | ||
|
|
8a75911567 | ||
|
|
8288ae5be8 | ||
|
|
9f40cd1bd9 | ||
|
|
39b4d62336 | ||
|
|
1faae313fa |
@@ -30,7 +30,7 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"next-auth": "^4.2.1"
|
||||
"next-auth": "^4.3.2"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
|
||||
@@ -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.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.2.1.tgz#042e4858d9f67b4f702d3a55bae0d2f04db3cac3"
|
||||
integrity sha512-XDtt7nqevkNf4EJ2zKAKkI+MFsURf11kx11vPwxrBYA1MHeqWwaWbGOUOI2ekNTvfAg4nTEJJUH3LV2cLrH3Tg==
|
||||
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==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@panva/hkdf" "^1.0.1"
|
||||
|
||||
@@ -89,7 +89,7 @@ The default redirect callback looks like this:
|
||||
callbacks: {
|
||||
async redirect({ url, baseUrl }) {
|
||||
// Allows relative callback URLs
|
||||
if (url.startsWith("/")) return new URL(url, baseUrl).toString()
|
||||
if (url.startsWith("/")) return `${baseUrl}${url}`
|
||||
// Allows callback URLs on the same origin
|
||||
else if (new URL(url).origin === baseUrl) return url
|
||||
return baseUrl
|
||||
|
||||
@@ -285,7 +285,6 @@ 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 */ }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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/error?error=Default`
|
||||
Example: `/auth/signin?error=Default`
|
||||
|
||||
## Theming
|
||||
|
||||
@@ -90,24 +90,16 @@ 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()
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
There is another, more fully styled example signin page available [here](https://github.com/ndom91/next-auth-example-sign-in-page).
|
||||
|
||||
### Email Sign in
|
||||
|
||||
If you create a custom sign in form for email sign in, you will need to submit both fields for the **email** address and **csrfToken** from **/api/auth/csrf** in a POST request to **/api/auth/signin/email**.
|
||||
@@ -128,22 +120,12 @@ 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:
|
||||
@@ -176,7 +158,6 @@ export default function SignIn({ csrfToken }) {
|
||||
)
|
||||
}
|
||||
|
||||
// This is the recommended way for Next.js 9.3 or newer
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: {
|
||||
@@ -184,15 +165,6 @@ 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:
|
||||
|
||||
@@ -111,9 +111,13 @@ 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.2).
|
||||
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 `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 it is not recommended, and in most cases, it is only supported for backward compatibility.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
## Example - Username / Password
|
||||
|
||||
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,9 +73,19 @@ 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 code
|
||||
### Example
|
||||
|
||||
You can specify more than one credentials provider by specifying a unique `id` for each one.
|
||||
|
||||
|
||||
@@ -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.js)
|
||||
- [Discord Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/discord.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
|
||||
@@ -94,20 +94,10 @@ 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()
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
@@ -44,6 +44,7 @@ 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
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "4.3.3",
|
||||
"version": "4.3.4",
|
||||
"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.0.0-0",
|
||||
"react-dom": "^17.0.2 || ^18.0.0-0"
|
||||
"react": "^17.0.2 || ^18",
|
||||
"react-dom": "^17.0.2 || ^18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"nodemailer": {
|
||||
|
||||
@@ -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"))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -65,28 +65,26 @@ export const mockSignOutResponse = {
|
||||
}
|
||||
|
||||
export const server = setupServer(
|
||||
rest.post("http://localhost/api/auth/signout", (req, res, ctx) =>
|
||||
rest.post("*/api/auth/signout", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockSignOutResponse))
|
||||
),
|
||||
rest.get("http://localhost/api/auth/session", (req, res, ctx) =>
|
||||
rest.get("*/api/auth/session", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockSession))
|
||||
),
|
||||
rest.get("http://localhost/api/auth/csrf", (req, res, ctx) =>
|
||||
rest.get("*/api/auth/csrf", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockCSRFToken))
|
||||
),
|
||||
rest.get("http://localhost/api/auth/providers", (req, res, ctx) =>
|
||||
rest.get("*/api/auth/providers", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockProviders))
|
||||
),
|
||||
rest.post("http://localhost/api/auth/signin/github", (req, res, ctx) =>
|
||||
rest.post("*/api/auth/signin/github", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockGithubResponse))
|
||||
),
|
||||
rest.post("http://localhost/api/auth/callback/credentials", (req, res, ctx) =>
|
||||
rest.post("*/api/auth/callback/credentials", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockCredentialsResponse))
|
||||
),
|
||||
rest.post("http://localhost/api/auth/signin/email", (req, res, ctx) =>
|
||||
rest.post("*/api/auth/signin/email", (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(mockEmailResponse))
|
||||
),
|
||||
rest.post("http://localhost/api/auth/_log", (req, res, ctx) =>
|
||||
res(ctx.status(200))
|
||||
)
|
||||
rest.post("*/api/auth/_log", (req, res, ctx) => res(ctx.status(200)))
|
||||
)
|
||||
|
||||
@@ -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"))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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"))
|
||||
})
|
||||
)
|
||||
|
||||
@@ -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("http://localhost/api/auth/signin/email", (req, res, ctx) => {
|
||||
rest.post("*/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("http://localhost/api/auth/signin/github", (req, res, ctx) => {
|
||||
rest.post("*/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("http://localhost/api/auth/providers", (req, res, ctx) =>
|
||||
rest.get("*/api/auth/providers", (req, res, ctx) =>
|
||||
res(ctx.status(500), ctx.json(errorMsg))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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("http://localhost/api/auth/signout", (req, res, ctx) =>
|
||||
rest.post("*/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("if url contains a hash during redirection a page reload happens", async () => {
|
||||
test.skip("if url contains a hash during redirection a page reload happens", async () => {
|
||||
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"
|
||||
|
||||
server.use(
|
||||
|
||||
@@ -120,7 +120,7 @@ export class SessionStore {
|
||||
option: CookieOption,
|
||||
req: {
|
||||
cookies?: Record<string, string>
|
||||
headers?: Record<string, string> | IncomingHttpHeaders
|
||||
headers?: Headers | IncomingHttpHeaders | Record<string, string>
|
||||
},
|
||||
logger: LoggerInstance | Console
|
||||
) {
|
||||
|
||||
@@ -47,7 +47,6 @@ 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.
|
||||
|
||||
@@ -3,6 +3,7 @@ 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 ".."
|
||||
|
||||
@@ -37,7 +38,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: NextApiRequest | Pick<NextApiRequest, "cookies" | "headers">
|
||||
req: NextRequest | NextApiRequest
|
||||
/**
|
||||
* 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
|
||||
@@ -90,8 +91,13 @@ export async function getToken<R extends boolean = false>(
|
||||
|
||||
let token = sessionStore.value
|
||||
|
||||
if (!token && req.headers.authorization?.split(" ")[0] === "Bearer") {
|
||||
const urlEncodedToken = req.headers.authorization.split(" ")[1]
|
||||
const authorizationHeader =
|
||||
req.headers instanceof Headers
|
||||
? req.headers.get("authorization")
|
||||
: req.headers.authorization
|
||||
|
||||
if (!token && authorizationHeader?.split(" ")[0] === "Bearer") {
|
||||
const urlEncodedToken = authorizationHeader.split(" ")[1]
|
||||
token = decodeURIComponent(urlEncodedToken)
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ async function handleMiddleware(
|
||||
return NextResponse.redirect(errorUrl)
|
||||
}
|
||||
|
||||
const token = await getToken({ req: req as any })
|
||||
const token = await getToken({ req })
|
||||
|
||||
const isAuthorized =
|
||||
(await options?.callbacks?.authorized?.({ req, token })) ?? !!token
|
||||
|
||||
@@ -134,8 +134,7 @@ export interface CampusUser {
|
||||
created_at: string
|
||||
updated_at: string | null
|
||||
}
|
||||
|
||||
export interface FortyTwoProfile extends UserData {
|
||||
export interface FortyTwoProfile extends UserData, Record<string, any> {
|
||||
groups: Array<{ id: string; name: string }>
|
||||
cursus_users: CursusUser[]
|
||||
projects_users: ProjectUser[]
|
||||
@@ -153,9 +152,9 @@ export interface FortyTwoProfile extends UserData {
|
||||
user: any | null
|
||||
}
|
||||
|
||||
export default function FortyTwo<
|
||||
P extends Record<string, any> = FortyTwoProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function FortyTwo<P extends FortyTwoProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "42-school",
|
||||
name: "42 School",
|
||||
|
||||
@@ -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 {
|
||||
export interface AppleProfile extends Record<string, any> {
|
||||
/**
|
||||
* 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 {
|
||||
auth_time: number
|
||||
}
|
||||
|
||||
export default function Apple<P extends Record<string, any> = AppleProfile>(
|
||||
export default function Apple<P extends AppleProfile>(
|
||||
options: Omit<OAuthUserConfig<P>, "clientSecret"> & {
|
||||
/**
|
||||
* Apple requires the client secret to be a JWT. You can generate one using the following script:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
interface AtlassianProfile {
|
||||
interface AtlassianProfile extends Record<string, any> {
|
||||
account_id: string
|
||||
name: string
|
||||
email: string
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface Auth0Profile {
|
||||
export interface Auth0Profile extends Record<string, any> {
|
||||
sub: string
|
||||
nickname: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export default function Auth0<P extends Record<string, any> = Auth0Profile>(
|
||||
export default function Auth0<P extends Auth0Profile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
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,
|
||||
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
|
||||
groups: string[]
|
||||
}
|
||||
|
||||
export default function Authentik<
|
||||
P extends Record<string, any> = AuthentikProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function Authentik<P extends AuthentikProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "authentik",
|
||||
name: "Authentik",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface AzureB2CProfile {
|
||||
export interface AzureB2CProfile extends Record<string, any> {
|
||||
exp: number
|
||||
nbf: number
|
||||
ver: string
|
||||
@@ -17,9 +17,7 @@ export interface AzureB2CProfile {
|
||||
tfp: string
|
||||
}
|
||||
|
||||
export default function AzureADB2C<
|
||||
P extends Record<string, any> = AzureB2CProfile
|
||||
>(
|
||||
export default function AzureADB2C<P extends AzureB2CProfile>(
|
||||
options: OAuthUserConfig<P> & {
|
||||
primaryUserFlow: string
|
||||
tenantId: string
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface AzureADProfile {
|
||||
export interface AzureADProfile extends Record<string, any> {
|
||||
sub: string
|
||||
nicname: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export default function AzureAD<P extends Record<string, any> = AzureADProfile>(
|
||||
export default function AzureAD<P extends AzureADProfile>(
|
||||
options: OAuthUserConfig<P> & {
|
||||
/**
|
||||
* https://docs.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0#examples
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface BattleNetProfile {
|
||||
export interface BattleNetProfile extends Record<string, any> {
|
||||
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 Record<string, any> = BattleNetProfile
|
||||
>(options: OAuthUserConfig<P> & { issuer: BattleNetIssuer }): OAuthConfig<P> {
|
||||
export default function BattleNet<P extends BattleNetProfile>(
|
||||
options: OAuthUserConfig<P> & { issuer: BattleNetIssuer }
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "battlenet",
|
||||
name: "Battle.net",
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface BoxyHQSAMLProfile {
|
||||
export interface BoxyHQSAMLProfile extends Record<string, any> {
|
||||
id: string
|
||||
email: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
}
|
||||
|
||||
export default function SAMLJackson<
|
||||
P extends Record<string, any> = BoxyHQSAMLProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function SAMLJackson<P extends BoxyHQSAMLProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "boxyhq-saml",
|
||||
name: "BoxyHQ SAML",
|
||||
@@ -34,4 +34,4 @@ export default function SAMLJackson<
|
||||
},
|
||||
options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface CognitoProfile {
|
||||
export interface CognitoProfile extends Record<string, any> {
|
||||
sub: string
|
||||
name: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export default function Cognito<P extends Record<string, any> = CognitoProfile>(
|
||||
export default function Cognito<P extends CognitoProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
/** @type {import(".").OAuthProvider} */
|
||||
export default function Discord(options) {
|
||||
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> {
|
||||
return {
|
||||
id: "discord",
|
||||
name: "Discord",
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface EVEOnlineProfile {
|
||||
export interface EVEOnlineProfile extends Record<string, any> {
|
||||
CharacterID: number
|
||||
CharacterName: string
|
||||
ExpiresOn: string
|
||||
@@ -10,9 +10,9 @@ export interface EVEOnlineProfile {
|
||||
IntellectualProperty: string
|
||||
}
|
||||
|
||||
export default function EVEOnline<
|
||||
P extends Record<string, any> = EVEOnlineProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function EVEOnline<P extends EVEOnlineProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "eveonline",
|
||||
name: "EVE Online",
|
||||
@@ -27,7 +27,7 @@ export default function EVEOnline<
|
||||
idToken: true,
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.CharacterID,
|
||||
id: String(profile.CharacterID),
|
||||
name: profile.CharacterName,
|
||||
email: null,
|
||||
image: `https://image.eveonline.com/Character/${profile.CharacterID}_128.jpg`,
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface FacebookProfile {
|
||||
id: string
|
||||
picture: { data: { url: string } }
|
||||
interface FacebookPictureData {
|
||||
url: string
|
||||
}
|
||||
|
||||
export default function Facebook<
|
||||
P extends Record<string, any> = FacebookProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
interface FacebookPicture {
|
||||
data: FacebookPictureData
|
||||
}
|
||||
export interface FacebookProfile extends Record<string, any> {
|
||||
id: string
|
||||
picture: FacebookPicture
|
||||
}
|
||||
|
||||
export default function Facebook<P extends FacebookProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "facebook",
|
||||
name: "Facebook",
|
||||
|
||||
@@ -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 {
|
||||
export interface FusionAuthProfile extends Record<string, any> {
|
||||
aud: string
|
||||
exp: number
|
||||
iat: number
|
||||
@@ -20,9 +20,7 @@ export interface FusionAuthProfile {
|
||||
sid: string
|
||||
}
|
||||
|
||||
export default function FusionAuth<
|
||||
P extends Record<string, any> = FusionAuthProfile
|
||||
>(
|
||||
export default function FusionAuth<P extends FusionAuthProfile>(
|
||||
// tenantId only needed if there is more than one tenant configured on the server
|
||||
options: OAuthUserConfig<P> & { tenantId?: string }
|
||||
): OAuthConfig<P> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface GoogleProfile {
|
||||
export interface GoogleProfile extends Record<string, any> {
|
||||
aud: string
|
||||
azp: string
|
||||
email: string
|
||||
@@ -18,7 +18,7 @@ export interface GoogleProfile {
|
||||
sub: string
|
||||
}
|
||||
|
||||
export default function Google<P extends Record<string, any> = GoogleProfile>(
|
||||
export default function Google<P extends GoogleProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -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 {
|
||||
export interface KakaoProfile extends Record<string, any> {
|
||||
id: number
|
||||
has_signed_up?: boolean
|
||||
connected_at?: DateTime
|
||||
@@ -66,7 +66,7 @@ export interface KakaoProfile {
|
||||
}
|
||||
}
|
||||
|
||||
export default function Kakao<P extends Record<string, any> = KakaoProfile>(
|
||||
export default function Kakao<P extends KakaoProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
@@ -81,7 +81,7 @@ export default function Kakao<P extends Record<string, any> = KakaoProfile>(
|
||||
},
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.id,
|
||||
id: String(profile.id),
|
||||
name: profile.kakao_account?.profile?.nickname,
|
||||
email: profile.kakao_account?.email,
|
||||
image: profile.kakao_account?.profile?.profile_image_url,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface KeycloakProfile {
|
||||
export interface KeycloakProfile extends Record<string, any> {
|
||||
exp: number
|
||||
iat: number
|
||||
auth_time: number
|
||||
@@ -24,9 +24,9 @@ export interface KeycloakProfile {
|
||||
user: any
|
||||
}
|
||||
|
||||
export default function Keycloak<
|
||||
P extends Record<string, any> = KeycloakProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function Keycloak<P extends KeycloakProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "keycloak",
|
||||
name: "Keycloak",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface LineProfile {
|
||||
export interface LineProfile extends Record<string, any> {
|
||||
iss: string
|
||||
sub: string
|
||||
aud: string
|
||||
@@ -12,7 +12,7 @@ export interface LineProfile {
|
||||
user: any
|
||||
}
|
||||
|
||||
export default function LINE<P extends Record<string, any> = LineProfile>(
|
||||
export default function LINE<P extends LineProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -8,7 +8,7 @@ interface Element {
|
||||
identifiers?: Identifier[]
|
||||
}
|
||||
|
||||
export interface LinkedInProfile {
|
||||
export interface LinkedInProfile extends Record<string, any> {
|
||||
id: string
|
||||
localizedFirstName: string
|
||||
localizedLastName: string
|
||||
@@ -19,9 +19,9 @@ export interface LinkedInProfile {
|
||||
}
|
||||
}
|
||||
|
||||
export default function LinkedIn<
|
||||
P extends Record<string, any> = LinkedInProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function LinkedIn<P extends LinkedInProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "linkedin",
|
||||
name: "LinkedIn",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
/** https://developers.naver.com/docs/login/profile/profile.md */
|
||||
export interface NaverProfile {
|
||||
export interface NaverProfile extends Record<string, any> {
|
||||
resultcode: string
|
||||
message: string
|
||||
response: {
|
||||
@@ -18,7 +18,7 @@ export interface NaverProfile {
|
||||
}
|
||||
}
|
||||
|
||||
export default function Naver<P extends Record<string, any> = NaverProfile>(
|
||||
export default function Naver<P extends NaverProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface OktaProfile {
|
||||
export interface OktaProfile extends Record<string, any> {
|
||||
iss: string
|
||||
ver: string
|
||||
sub: string
|
||||
@@ -34,7 +34,7 @@ export interface OktaProfile {
|
||||
c_hash: string
|
||||
}
|
||||
|
||||
export default function Okta<P extends Record<string, any> = OktaProfile>(
|
||||
export default function Okta<P extends OktaProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface OsuUserCompact {
|
||||
username: string
|
||||
}
|
||||
|
||||
export interface OsuProfile extends OsuUserCompact {
|
||||
export interface OsuProfile extends OsuUserCompact, Record<string, any> {
|
||||
discord: string | null
|
||||
has_supported: boolean
|
||||
interests: string | null
|
||||
@@ -49,7 +49,7 @@ export interface OsuProfile extends OsuUserCompact {
|
||||
is_restricted: boolean
|
||||
}
|
||||
|
||||
export default function Osu<P extends Record<string, any> = OsuProfile>(
|
||||
export default function Osu<P extends OsuProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface PatreonProfile {
|
||||
export interface PatreonProfile extends Record<string, any> {
|
||||
sub: string
|
||||
nickname: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export default function Patreon<P extends Record<string, any> = PatreonProfile>(
|
||||
export default function Patreon<P extends PatreonProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface PipedriveProfile {
|
||||
export interface PipedriveProfile extends Record<string, any> {
|
||||
success: boolean
|
||||
data: {
|
||||
id: number
|
||||
@@ -35,9 +35,9 @@ export interface PipedriveProfile {
|
||||
}
|
||||
}
|
||||
|
||||
export default function Pipedrive<
|
||||
P extends Record<string, any> = PipedriveProfile
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function Pipedrive<P extends PipedriveProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "pipedrive",
|
||||
name: "Pipedrive",
|
||||
@@ -48,7 +48,7 @@ export default function Pipedrive<
|
||||
userinfo: "https://api.pipedrive.com/users/me",
|
||||
profile: ({ data: profile }) => {
|
||||
return {
|
||||
id: profile.id,
|
||||
id: String(profile.id),
|
||||
name: profile.name,
|
||||
email: profile.email,
|
||||
image: profile.icon_url,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface SlackProfile {
|
||||
export interface SlackProfile extends Record<string, any> {
|
||||
ok: boolean
|
||||
sub: string
|
||||
"https://slack.com/user_id": string
|
||||
@@ -32,7 +32,7 @@ export interface SlackProfile {
|
||||
"https://slack.com/team_image_default": boolean
|
||||
}
|
||||
|
||||
export default function Slack<P extends Record<string, any> = SlackProfile>(
|
||||
export default function Slack<P extends SlackProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -4,13 +4,13 @@ export interface SpotifyImage {
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface SpotifyProfile {
|
||||
export interface SpotifyProfile extends Record<string, any> {
|
||||
id: string
|
||||
display_name: string
|
||||
email: string
|
||||
images: SpotifyImage[]
|
||||
}
|
||||
export default function Spotify<P extends Record<string, any> = SpotifyProfile>(
|
||||
export default function Spotify<P extends SpotifyProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface TraktUser {
|
||||
export interface TraktUser extends Record<string, any> {
|
||||
username: string
|
||||
private: boolean
|
||||
name: string
|
||||
@@ -15,9 +15,9 @@ export interface TraktUser {
|
||||
images: { avatar: { full: string } }
|
||||
}
|
||||
|
||||
export default function Trakt<
|
||||
P extends Record<string, any> = TraktUser
|
||||
>(options: OAuthUserConfig<P>): OAuthConfig<P> {
|
||||
export default function Trakt<P extends TraktUser>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
id: "trakt",
|
||||
name: "Trakt",
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface TwitchProfile {
|
||||
export interface TwitchProfile extends Record<string, any> {
|
||||
sub: string
|
||||
preferred_username: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export default function Twitch<P extends Record<string, any> = TwitchProfile>(
|
||||
export default function Twitch<P extends TwitchProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface WorkOSProfile {
|
||||
export interface WorkOSProfile extends Record<string, any> {
|
||||
object: string
|
||||
id: string
|
||||
organization_id: string
|
||||
@@ -15,10 +15,11 @@ export interface WorkOSProfile {
|
||||
email: string
|
||||
lastName: string
|
||||
firstName: string
|
||||
picture: string
|
||||
}
|
||||
}
|
||||
|
||||
export default function WorkOS<P extends Record<string, any> = WorkOSProfile>(
|
||||
export default function WorkOS<P extends WorkOSProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
const { issuer = "https://api.workos.com/" } = options
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
export interface ZoomProfile {
|
||||
export interface ZoomProfile extends Record<string, any> {
|
||||
id: string
|
||||
first_name: string
|
||||
last_name: string
|
||||
@@ -29,7 +29,7 @@ export interface ZoomProfile {
|
||||
status: string
|
||||
}
|
||||
|
||||
export default function Zoom<P extends Record<string, any> = ZoomProfile>(
|
||||
export default function Zoom<P extends ZoomProfile>(
|
||||
options: OAuthUserConfig<P>
|
||||
): OAuthConfig<P> {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user