Compare commits

...

15 Commits

Author SHA1 Message Date
Balázs Orbán
c6903d3e85 chore. bump version 2022-04-28 12:18:48 +02:00
Balázs Orbán
a74d215745 Revert "fix: loosen env variable URL fallback (#4443)" (#4481)
This reverts commit d4fb7af6f5.
2022-04-28 11:50:29 +02:00
Kot
18174fae36 docs: Clarify code_challenge_method RFC requirement (#4464) 2022-04-28 11:45:31 +02:00
Balázs Orbán
d4fb7af6f5 fix: loosen env variable URL fallback (#4443)
Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-28 11:42:40 +02:00
dependabot[bot]
bc15e2866e chore(deps): bump next-auth in /apps/playground-sveltekit (#4451)
Bumps [next-auth](https://github.com/nextauthjs/next-auth) from 4.2.1 to 4.3.2.
- [Release notes](https://github.com/nextauthjs/next-auth/releases)
- [Changelog](https://github.com/nextauthjs/next-auth/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nextauthjs/next-auth/compare/v4.2.1...next-auth@v4.3.2)

---
updated-dependencies:
- dependency-name: next-auth
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-28 11:42:18 +02:00
Jonas Strassel
aee5ec2e4f docs: remove redudant and deprecated doc (#4475)
... as `session.jwt` has been replaced with `session.strategy: 'jwt'`
2022-04-28 11:42:06 +02:00
Balázs Orbán
f0ed23acf6 fix: allow react@18 as peer dependency 2022-04-28 11:35:14 +02:00
Lluis Agusti
fb4bbc3b08 fix(ts): handle NextRequest type (#4472)
* fix(jwt): handle NextRequest

* fix(cookie): Headers from fetch request

* Update packages/next-auth/src/jwt/index.ts

* fix: tests

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2022-04-28 11:22:49 +02:00
Smultar
4c832f855e Fixes 404 error, when visiting the options link (#4462)
The current link leads to nowhere.
2022-04-25 16:57:30 +02:00
Nico Domino
e3ace6e649 chore: add SIWE and signin example links (#4463)
* chore(docs): add link to SIWE example app / tutorial

* chore(docs): add link to example signin page and cleanup

* chore: update copy for SIWE credentials provider example
2022-04-24 14:18:03 +02:00
Jon Parton
8a75911567 fix(client): update 'signin' page error example (#4412)
Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-22 18:24:33 +02:00
Lluis Agusti
8288ae5be8 fix(providers): profile types (#4202) 2022-04-22 13:15:24 +02:00
Jiyeol Lee
9f40cd1bd9 fix(client): add additional type (#4402)
* Add additional type
* do not cast to 'any' anymore
* add missing import
* import NextRequest from next/server

Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-22 13:10:10 +02:00
Thang Vu
39b4d62336 docs: remove error event in config options (#4406) 2022-04-22 10:38:26 +02:00
Balázs Orbán
1faae313fa docs: update callbacks 2022-04-20 19:27:01 +02:00
51 changed files with 191 additions and 188 deletions

View File

@@ -30,7 +30,7 @@
"type": "module",
"dependencies": {
"cookie": "0.4.1",
"next-auth": "^4.2.1"
"next-auth": "^4.3.2"
},
"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.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"

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 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

View File

@@ -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 */ }
}
```

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/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:

View File

@@ -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.
---

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
## 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.

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.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.

View File

@@ -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()
}
}
*/
```

View File

@@ -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

View File

@@ -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": {

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,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)))
)

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("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))
)
)

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("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(

View File

@@ -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
) {

View File

@@ -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.

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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",

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 {
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:

View File

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

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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",

View File

@@ -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,
}
}
}

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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`,

View File

@@ -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",

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 {
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> {

View File

@@ -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 {

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 {
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,

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 {