diff --git a/__fixtures__/test-project/api/package.json b/__fixtures__/test-project/api/package.json index 4c1dca6f062b..d0ead7dcc0a4 100644 --- a/__fixtures__/test-project/api/package.json +++ b/__fixtures__/test-project/api/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@redwoodjs/api": "3.2.0", - "@redwoodjs/auth-providers-api": "^0.0.1", + "@redwoodjs/auth-dbauth-api": "0.0.2", "@redwoodjs/graphql-server": "3.2.0" } } diff --git a/__fixtures__/test-project/api/src/functions/auth.ts b/__fixtures__/test-project/api/src/functions/auth.ts index 28b7084fa1eb..2d7a5031e0da 100644 --- a/__fixtures__/test-project/api/src/functions/auth.ts +++ b/__fixtures__/test-project/api/src/functions/auth.ts @@ -3,7 +3,7 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda' import { DbAuthHandler, DbAuthHandlerOptions, -} from '@redwoodjs/auth-providers-api' +} from '@redwoodjs/auth-dbauth-api' import { db } from 'src/lib/db' diff --git a/__fixtures__/test-project/api/src/functions/graphql.ts b/__fixtures__/test-project/api/src/functions/graphql.ts index 2aca7a75898a..5d8db6ab8f2a 100644 --- a/__fixtures__/test-project/api/src/functions/graphql.ts +++ b/__fixtures__/test-project/api/src/functions/graphql.ts @@ -1,4 +1,4 @@ -import { dbAuthAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api' +import { authDecoder } from '@redwoodjs/auth-dbauth-api' import { createGraphQLHandler } from '@redwoodjs/graphql-server' import directives from 'src/directives/**/*.{js,ts}' diff --git a/__fixtures__/test-project/package.json b/__fixtures__/test-project/package.json index e3e54b9f9abc..be6d6bf1bd0b 100644 --- a/__fixtures__/test-project/package.json +++ b/__fixtures__/test-project/package.json @@ -8,6 +8,7 @@ ] }, "devDependencies": { + "@redwoodjs/auth-dbauth-setup": "0.0.2", "@redwoodjs/core": "3.2.0" }, "eslintConfig": { diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json index 403558fb813d..d0ac0975de0a 100644 --- a/__fixtures__/test-project/web/package.json +++ b/__fixtures__/test-project/web/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@redwoodjs/auth": "3.2.0", - "@redwoodjs/auth-providers-web": "^0.0.1", + "@redwoodjs/auth-dbauth-web": "0.0.2", "@redwoodjs/forms": "3.2.0", "@redwoodjs/router": "3.2.0", "@redwoodjs/web": "3.2.0", diff --git a/__fixtures__/test-project/web/src/auth.ts b/__fixtures__/test-project/web/src/auth.ts index 6b66206d5583..4a620e5ecf37 100644 --- a/__fixtures__/test-project/web/src/auth.ts +++ b/__fixtures__/test-project/web/src/auth.ts @@ -1,3 +1,3 @@ -import { createDbAuth } from '@redwoodjs/auth-providers-web' +import { createDbAuth } from '@redwoodjs/auth-dbauth-web' export const { AuthProvider, useAuth } = createDbAuth() diff --git a/package.json b/package.json index 681e0c0c4f39..cc2aec095fac 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "license": "MIT", "workspaces": [ "packages/*", - "packages/auth-providers/**/*" + "packages/auth-providers/*/*" ], "scripts": { "build": "lerna run build", diff --git a/packages/auth-providers-api/package.json b/packages/auth-providers-api/package.json index 1f0feda067b0..181d7a8da39e 100644 --- a/packages/auth-providers-api/package.json +++ b/packages/auth-providers-api/package.json @@ -25,64 +25,34 @@ "dependencies": { "@babel/runtime-corejs3": "7.20.6", "core-js": "3.26.1", - "jsonwebtoken": "8.5.1", - "uuid": "9.0.0" + "jsonwebtoken": "8.5.1" }, "devDependencies": { - "@auth0/auth0-spa-js": "1.22.5", - "@azure/msal-browser": "2.30.0", "@babel/cli": "7.19.3", "@babel/core": "7.20.5", - "@clerk/clerk-js": "3.17.0", - "@clerk/clerk-react": "3.5.1", - "@clerk/clerk-sdk-node": "3.9.2", - "@clerk/types": "2.21.0", "@magic-sdk/admin": "1.4.1", "@nhost/hasura-auth-js": "1.4.1", "@nhost/nhost-js": "1.4.10", "@okta/jwt-verifier": "2.6.0", "@okta/okta-auth-js": "6.9.0", - "@redwoodjs/auth": "3.2.0", - "@redwoodjs/cli-helpers": "3.2.0", - "@simplewebauthn/browser": "6.2.1", - "@simplewebauthn/typescript-types": "6.2.1", - "@supabase/supabase-js": "1.35.7", + "@redwoodjs/api": "3.2.0", + "@types/aws-lambda": "8.10.107", "@types/jsonwebtoken": "8.5.9", - "@types/netlify-identity-widget": "1.9.3", - "@types/react": "17.0.50", - "@types/uuid": "8.3.4", - "firebase": "9.10.0", - "firebase-admin": "10.3.0", "gotrue-js": "0.9.29", "jest": "29.3.1", "magic-sdk": "9.1.1", - "netlify-identity-widget": "1.9.2", - "react": "17.0.2", - "supertokens-auth-react": "0.26.5", "typescript": "4.7.4" }, "peerDependencies": { - "@clerk/clerk-react": "3.5.1", - "@clerk/clerk-sdk-node": "3.9.2", "@magic-sdk/admin": "1.4.1", - "@okta/jwt-verifier": "2.6.0", - "firebase-admin": "10.3.0" + "@okta/jwt-verifier": "2.6.0" }, "peerDependenciesMeta": { - "@clerk/clerk-react": { - "optional": true - }, - "@clerk/clerk-sdk-node": { - "optional": true - }, "@magic-sdk/admin": { "optional": true }, "@okta/jwt-verifier": { "optional": true - }, - "firebase-admin": { - "optional": true } }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers-api/src/index.ts b/packages/auth-providers-api/src/index.ts index 2e493a44abab..1dccb2acf21e 100644 --- a/packages/auth-providers-api/src/index.ts +++ b/packages/auth-providers-api/src/index.ts @@ -1,11 +1,5 @@ -export { authDecoder as clerkAuthDecoder } from './clerk/decoder' -export { authDecoder as dbAuthAuthDecoder } from './dbAuth/decoder' export { authDecoder as ethereumAuthDecoder } from './ethereum/decoder' export { authDecoder as goTrueAuthDecoder } from './goTrue/decoder' export { authDecoder as magicLinkAuthDecoder } from './magicLink/decoder' export { authDecoder as nhostAuthDecoder } from './nhost/decoder' export { authDecoder as oktaAuthDecoder } from './okta/decoder' -export { authDecoder as supabaseAuthDecoder } from './supabase/decoder' -export { authDecoder as supertokensAuthDecoder } from './supertokens/decoder' - -export { hashPassword, DbAuthHandler, DbAuthHandlerOptions } from './dbAuth' diff --git a/packages/auth-providers-setup/jest.config.js b/packages/auth-providers-setup/jest.config.js index e691bb8f6dbd..dee127c25474 100644 --- a/packages/auth-providers-setup/jest.config.js +++ b/packages/auth-providers-setup/jest.config.js @@ -1,5 +1,4 @@ /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { - testEnvironment: 'jest-environment-jsdom', testPathIgnorePatterns: ['fixtures', 'dist'], } diff --git a/packages/auth-providers-setup/package.json b/packages/auth-providers-setup/package.json index 877dd703c33c..7e3c7efbd572 100644 --- a/packages/auth-providers-setup/package.json +++ b/packages/auth-providers-setup/package.json @@ -24,16 +24,13 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", - "@redwoodjs/auth": "3.2.0", "@redwoodjs/cli-helpers": "3.2.0", - "core-js": "3.26.1", - "secure-random-password": "0.2.3" + "core-js": "3.26.1" }, "devDependencies": { "@babel/cli": "7.19.3", "@babel/core": "7.20.5", - "@types/react": "17.0.50", - "@types/secure-random-password": "0.2.1", + "@types/yargs": "17.0.13", "jest": "29.3.1", "typescript": "4.7.4" }, diff --git a/packages/auth-providers-setup/src/clerk/setup.ts b/packages/auth-providers-setup/src/clerk/setup.ts deleted file mode 100644 index bf1c3f374f69..000000000000 --- a/packages/auth-providers-setup/src/clerk/setup.ts +++ /dev/null @@ -1,35 +0,0 @@ -import yargs from 'yargs' - -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' - -export const command = 'clerk' -export const description = 'Generate an auth configuration for Clerk' -export const builder = (yargs: yargs.Argv) => { - return standardAuthBuilder(yargs) -} - -interface Args { - rwVersion: string - force: boolean -} - -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - authDecoderImport: - "import { clerkAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - provider: 'clerk', - webPackages: ['@clerk/clerk-react', '@redwoodjs/auth-providers-web'], - apiPackages: ['@clerk/clerk-sdk-node', '@redwoodjs/auth-providers-api'], - notes: [ - 'You will need to add three environment variables with your Clerk URL, API key and JWT key.', - 'Check out web/src/auth.{js,tsx} for the variables you need to add.', - 'See also: https://redwoodjs.com/docs/authentication#clerk', - ], - }) -} diff --git a/packages/auth-providers-setup/src/dbAuth/templates/web/auth.ts.template b/packages/auth-providers-setup/src/dbAuth/templates/web/auth.ts.template deleted file mode 100644 index 6b66206d5583..000000000000 --- a/packages/auth-providers-setup/src/dbAuth/templates/web/auth.ts.template +++ /dev/null @@ -1,3 +0,0 @@ -import { createDbAuth } from '@redwoodjs/auth-providers-web' - -export const { AuthProvider, useAuth } = createDbAuth() diff --git a/packages/auth-providers-setup/src/dbAuth/templates/web/auth.webAuthn.ts.template b/packages/auth-providers-setup/src/dbAuth/templates/web/auth.webAuthn.ts.template deleted file mode 100644 index d9ad74f6e947..000000000000 --- a/packages/auth-providers-setup/src/dbAuth/templates/web/auth.webAuthn.ts.template +++ /dev/null @@ -1,4 +0,0 @@ -import { createDbAuth } from '@redwoodjs/auth-providers-web' -import WebAuthnClient from '@redwoodjs/auth-providers-web/webAuthn' - -export const { AuthProvider, useAuth } = createDbAuth(WebAuthnClient) diff --git a/packages/auth-providers-setup/src/ethereum/setup.ts b/packages/auth-providers-setup/src/ethereum/setup.ts index c2fa5c43ad8a..9dc4bf4ebf39 100644 --- a/packages/auth-providers-setup/src/ethereum/setup.ts +++ b/packages/auth-providers-setup/src/ethereum/setup.ts @@ -1,46 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'ethereum' export const description = 'Generate an auth configuration for Ethereum' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'ethereum', - authDecoderImport: - "import { ethereumAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: [ - '@redwoodjs/auth-providers-api', - 'ethereumjs-util', - 'eth-sig-util', - 'jsonwebtoken', - ], - webPackages: [ - '@redwoodjs/auth-providers-web', - '@oneclickdapp/ethereum-auth', - '@apollo/client', - ], - notes: [ - 'There are a couple more things you need to do!', - 'Please see the readme for instructions:', - 'https://github.com/oneclickdapp/ethereum-auth', - 'This is a FOSS community-maintained package.', - 'Help us make it better!', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers-setup/src/ethereum/setupHandler.ts b/packages/auth-providers-setup/src/ethereum/setupHandler.ts new file mode 100644 index 000000000000..c45e1acd4338 --- /dev/null +++ b/packages/auth-providers-setup/src/ethereum/setupHandler.ts @@ -0,0 +1,35 @@ +import fs from 'fs' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse(fs.readFileSync('../package.json', 'utf-8')) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'ethereum', + authDecoderImport: + "import { ethereumAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", + apiPackages: [ + `@redwoodjs/auth-providers-api@${version}`, + 'ethereumjs-util', + 'eth-sig-util', + 'jsonwebtoken', + ], + webPackages: [ + `@redwoodjs/auth-providers-web@${version}`, + '@oneclickdapp/ethereum-auth', + '@apollo/client', + ], + notes: [ + 'There are a couple more things you need to do!', + 'Please see the readme for instructions:', + 'https://github.com/oneclickdapp/ethereum-auth', + 'This is a FOSS community-maintained package.', + 'Help us make it better!', + ], + }) +} diff --git a/packages/auth-providers-setup/src/goTrue/setup.ts b/packages/auth-providers-setup/src/goTrue/setup.ts index 1491a9cd910d..ca9e039936d0 100644 --- a/packages/auth-providers-setup/src/goTrue/setup.ts +++ b/packages/auth-providers-setup/src/goTrue/setup.ts @@ -1,35 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'goTrue' export const description = 'Generate an auth configuration for goTrue' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'goTrue', - authDecoderImport: - "import { goTrueAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: ['@redwoodjs/auth-providers-api'], - webPackages: ['gotrue-js', '@redwoodjs/auth-providers-web'], - notes: [ - 'You will need to enable Identity on your Netlify site and set APIUrl', - 'to your API endpoint in your GoTrue client config.', - 'See: https://redwoodjs.com/docs/auth/gotrue', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers-setup/src/goTrue/setupHandler.ts b/packages/auth-providers-setup/src/goTrue/setupHandler.ts new file mode 100644 index 000000000000..e393dfbf626e --- /dev/null +++ b/packages/auth-providers-setup/src/goTrue/setupHandler.ts @@ -0,0 +1,24 @@ +import fs from 'fs' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse(fs.readFileSync('../package.json', 'utf-8')) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'goTrue', + authDecoderImport: + "import { goTrueAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", + apiPackages: [`@redwoodjs/auth-providers-api@${version}`], + webPackages: ['gotrue-js', `@redwoodjs/auth-providers-web@${version}`], + notes: [ + 'You will need to enable Identity on your Netlify site and set APIUrl', + 'to your API endpoint in your GoTrue client config.', + 'See: https://redwoodjs.com/docs/auth/gotrue', + ], + }) +} diff --git a/packages/auth-providers-setup/src/index.ts b/packages/auth-providers-setup/src/index.ts index 439c24455654..885ab3268413 100644 --- a/packages/auth-providers-setup/src/index.ts +++ b/packages/auth-providers-setup/src/index.ts @@ -1,9 +1,5 @@ -export * as setupAuthClerkCommand from './clerk/setup' -export * as setupAuthDbAuthCommand from './dbAuth/setup' export * as setupAuthEthereumCommand from './ethereum/setup' export * as setupAuthGoTrueCommand from './goTrue/setup' export * as setupAuthMagicLinkCommand from './magicLink/setup' export * as setupAuthNhostCommand from './nhost/setup' export * as setupAuthOktaCommand from './okta/setup' -export * as setupAuthSupabaseCommand from './supabase/setup' -export * as setupAuthSupertokensCommand from './supertokens/setup' diff --git a/packages/auth-providers-setup/src/magicLink/setup.ts b/packages/auth-providers-setup/src/magicLink/setup.ts index aff7330c51b0..1affed35c848 100644 --- a/packages/auth-providers-setup/src/magicLink/setup.ts +++ b/packages/auth-providers-setup/src/magicLink/setup.ts @@ -1,35 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'magicLink' export const description = 'Generate an auth configuration for MagicLink' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'magicLink', - authDecoderImport: - "import { magicLinkAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: ['@redwoodjs/auth-providers-api', '@magic-sdk/admin'], - webPackages: ['@redwoodjs/auth-providers-web', 'magic-sdk'], - notes: [ - 'To get your application keys, go to https://dashboard.magic.link/login ', - 'Then navigate to the API keys add them to your .env config options.', - 'See: https://redwoodjs.com/docs/authentication#for-magiclink', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers-setup/src/magicLink/setupHandler.ts b/packages/auth-providers-setup/src/magicLink/setupHandler.ts new file mode 100644 index 000000000000..2e3ba6a0802e --- /dev/null +++ b/packages/auth-providers-setup/src/magicLink/setupHandler.ts @@ -0,0 +1,27 @@ +import fs from 'fs' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse(fs.readFileSync('../package.json', 'utf-8')) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'magicLink', + authDecoderImport: + "import { magicLinkAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", + apiPackages: [ + `@redwoodjs/auth-providers-api@${version}`, + '@magic-sdk/admin', + ], + webPackages: [`@redwoodjs/auth-providers-web@${version}`, 'magic-sdk'], + notes: [ + 'To get your application keys, go to https://dashboard.magic.link/login ', + 'Then navigate to the API keys add them to your .env config options.', + 'See: https://redwoodjs.com/docs/authentication#for-magiclink', + ], + }) +} diff --git a/packages/auth-providers-setup/src/nhost/setup.ts b/packages/auth-providers-setup/src/nhost/setup.ts index 6fb52a44db01..b3237f3fab09 100644 --- a/packages/auth-providers-setup/src/nhost/setup.ts +++ b/packages/auth-providers-setup/src/nhost/setup.ts @@ -1,34 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'nhost' export const description = 'Generate an auth configuration for nhost' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'nhost', - authDecoderImport: - "import { nhostAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: ['@redwoodjs/auth-providers-api'], - webPackages: ['@redwoodjs/auth-providers-web', '@nhost/nhost-js'], - notes: [ - "You will need to add your project's backend URL (NHOST_BACKEND_URL) and", - 'JWT Key Secret (NHOST_JWT_SECRET) to your .env file.', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers-setup/src/nhost/setupHandler.ts b/packages/auth-providers-setup/src/nhost/setupHandler.ts new file mode 100644 index 000000000000..9a3ca356f37f --- /dev/null +++ b/packages/auth-providers-setup/src/nhost/setupHandler.ts @@ -0,0 +1,26 @@ +import fs from 'fs' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse(fs.readFileSync('../package.json', 'utf-8')) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'nhost', + authDecoderImport: + "import { nhostAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", + apiPackages: [`@redwoodjs/auth-providers-api@${version}`], + webPackages: [ + `@redwoodjs/auth-providers-web@${version}`, + '@nhost/nhost-js', + ], + notes: [ + "You will need to add your project's backend URL (NHOST_BACKEND_URL) and", + 'JWT Key Secret (NHOST_JWT_SECRET) to your .env file.', + ], + }) +} diff --git a/packages/auth-providers-setup/src/okta/setup.ts b/packages/auth-providers-setup/src/okta/setup.ts index 18117f5812a5..bdb02d2e5949 100644 --- a/packages/auth-providers-setup/src/okta/setup.ts +++ b/packages/auth-providers-setup/src/okta/setup.ts @@ -1,30 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'okta' export const description = 'Generate an auth configuration for Okta' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'okta', - authDecoderImport: - "import { oktaAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - webPackages: ['@okta/okta-auth-js', '@redwoodjs/auth-providers-web'], - apiPackages: ['@okta/jwt-verifier', '@redwoodjs/auth-providers-api'], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers-setup/src/okta/setupHandler.ts b/packages/auth-providers-setup/src/okta/setupHandler.ts new file mode 100644 index 000000000000..0e1107b3df96 --- /dev/null +++ b/packages/auth-providers-setup/src/okta/setupHandler.ts @@ -0,0 +1,25 @@ +import fs from 'fs' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse(fs.readFileSync('../package.json', 'utf-8')) + +export const handler = async ({ force: forceArg }: Args) => { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'okta', + authDecoderImport: + "import { oktaAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", + webPackages: [ + '@okta/okta-auth-js', + `@redwoodjs/auth-providers-web@${version}`, + ], + apiPackages: [ + '@okta/jwt-verifier', + `@redwoodjs/auth-providers-api@${version}`, + ], + }) +} diff --git a/packages/auth-providers-setup/src/supabase/setup.ts b/packages/auth-providers-setup/src/supabase/setup.ts deleted file mode 100644 index 2497900762f4..000000000000 --- a/packages/auth-providers-setup/src/supabase/setup.ts +++ /dev/null @@ -1,38 +0,0 @@ -import yargs from 'yargs' - -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' - -export const command = 'supabase' -export const description = 'Generate an auth configuration for Supabase' -export const builder = (yargs: yargs.Argv) => { - return standardAuthBuilder(yargs) -} - -interface Args { - rwVersion: string - force: boolean -} - -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'supabase', - authDecoderImport: - "import { supabaseAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: ['@redwoodjs/auth-providers-api'], - webPackages: [ - '@redwoodjs/auth-providers-web', - '@supabase/supabase-js@1.35.7', - ], - notes: [ - 'You will need to add your Supabase URL (SUPABASE_URL), public API KEY,', - 'and JWT SECRET (SUPABASE_KEY, and SUPABASE_JWT_SECRET) to your .env file.', - 'See: https://supabase.io/docs/library/getting-started#reference', - ], - }) -} diff --git a/packages/auth-providers-setup/src/supertokens/setup.ts b/packages/auth-providers-setup/src/supertokens/setup.ts deleted file mode 100644 index d575555ec53f..000000000000 --- a/packages/auth-providers-setup/src/supertokens/setup.ts +++ /dev/null @@ -1,35 +0,0 @@ -import yargs from 'yargs' - -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' - -export const command = 'supertokens' -export const description = 'Generate an auth configuration for SuperTokens' -export const builder = (yargs: yargs.Argv) => { - return standardAuthBuilder(yargs) -} - -interface Args { - rwVersion: string - force: boolean -} - -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'supertokens', - authDecoderImport: - "import { supertokensAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - apiPackages: ['@redwoodjs/auth-providers-api', 'supertokens-node'], - webPackages: ['@redwoodjs/auth-providers-web', 'supertokens-auth-react'], - notes: [ - "We've generated some example recipe implementations, but do feel free", - 'to switch to something else that better fit your needs.', - 'See: https://supertokens.com/docs/guides', - ], - }) -} diff --git a/packages/auth-providers-web/jest.config.js b/packages/auth-providers-web/jest.config.js index 4c937d832dc1..e691bb8f6dbd 100644 --- a/packages/auth-providers-web/jest.config.js +++ b/packages/auth-providers-web/jest.config.js @@ -1,8 +1,5 @@ -const path = require('path') - /** @type {import('@jest/types').Config.InitialOptions} */ module.exports = { testEnvironment: 'jest-environment-jsdom', testPathIgnorePatterns: ['fixtures', 'dist'], - resolver: path.resolve(__dirname, './resolver.js'), } diff --git a/packages/auth-providers-web/package.json b/packages/auth-providers-web/package.json index 528c9c016311..f53124a6d3b0 100644 --- a/packages/auth-providers-web/package.json +++ b/packages/auth-providers-web/package.json @@ -25,60 +25,32 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", - "core-js": "3.26.1", - "uuid": "9.0.0" + "core-js": "3.26.1" }, "devDependencies": { - "@auth0/auth0-spa-js": "1.22.5", - "@azure/msal-browser": "2.30.0", "@babel/cli": "7.19.3", "@babel/core": "7.20.5", - "@clerk/clerk-js": "3.17.0", - "@clerk/clerk-react": "3.5.1", - "@clerk/clerk-sdk-node": "3.9.2", - "@clerk/types": "2.21.0", "@nhost/hasura-auth-js": "1.4.1", "@nhost/nhost-js": "1.4.10", "@okta/okta-auth-js": "6.9.0", "@redwoodjs/auth": "3.2.0", - "@simplewebauthn/browser": "6.2.1", - "@simplewebauthn/typescript-types": "6.2.1", - "@supabase/supabase-js": "1.35.7", - "@types/netlify-identity-widget": "1.9.3", "@types/react": "17.0.50", - "@types/uuid": "8.3.4", - "firebase": "9.10.0", - "firebase-admin": "10.3.0", "gotrue-js": "0.9.29", "jest": "29.3.1", "magic-sdk": "9.1.1", - "netlify-identity-widget": "1.9.2", "react": "17.0.2", - "supertokens-auth-react": "0.26.5", "typescript": "4.7.4" }, "peerDependencies": { - "@clerk/clerk-react": "3.5.1", - "@clerk/clerk-sdk-node": "3.9.2", "@magic-sdk/admin": "1.4.1", - "@okta/jwt-verifier": "2.6.0", - "firebase-admin": "10.3.0" + "@okta/jwt-verifier": "2.6.0" }, "peerDependenciesMeta": { - "@clerk/clerk-react": { - "optional": true - }, - "@clerk/clerk-sdk-node": { - "optional": true - }, "@magic-sdk/admin": { "optional": true }, "@okta/jwt-verifier": { "optional": true - }, - "firebase-admin": { - "optional": true } }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers-web/resolver.js b/packages/auth-providers-web/resolver.js deleted file mode 100644 index 4fb0bab11bef..000000000000 --- a/packages/auth-providers-web/resolver.js +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-env node */ - -// See these threads: -// - https://github.com/facebook/jest/issues/12770 -// - https://github.com/microsoft/accessibility-insights-web/pull/5421#issuecomment-1109168149. -// -// TL;DR, we need to resolve the firebase packages to a CommonJS version. So we -// leverage jest's default resolver, but use `packageFilter` to process parsed -// `package.json` before resolution. In doing so, we only override how jest -// resolves the firebase packages. -module.exports = (path, options) => { - return options.defaultResolver(path, { - ...options, - packageFilter: (pkg) => { - if (pkg.name === 'firebase') { - pkg.exports['./auth'].default = pkg.exports['./auth'].node.require - } - - if (['@firebase/auth', '@firebase/util'].includes(pkg.name)) { - pkg.exports['.'].default = pkg.exports['.'].node.require - } - - return pkg - }, - }) -} diff --git a/packages/auth-providers-web/src/index.ts b/packages/auth-providers-web/src/index.ts index 8543effd188a..444e8b956b8e 100644 --- a/packages/auth-providers-web/src/index.ts +++ b/packages/auth-providers-web/src/index.ts @@ -1,9 +1,5 @@ -export { createClerkAuth } from './clerk/clerk' -export { createDbAuth } from './dbAuth/dbAuth' export { createEthereumAuth } from './ethereum/ethereum' export { createGoTrueAuth } from './goTrue/goTrue' export { createMagicLinkAuth } from './magicLink/magicLink' export { createNhostAuth } from './nhost/nhost' export { createOktaAuth } from './okta/okta' -export { createSupabaseAuth } from './supabase/supabase' -export { createSuperTokensAuth } from './supertokens/supertokens' diff --git a/packages/auth-providers-web/webAuthn/index.js b/packages/auth-providers-web/webAuthn/index.js deleted file mode 100644 index e6891677d0b2..000000000000 --- a/packages/auth-providers-web/webAuthn/index.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-env es6, commonjs */ -module.exports = require('../dist/dbAuth/webAuthn') diff --git a/packages/auth-providers-web/webAuthn/package.json b/packages/auth-providers-web/webAuthn/package.json deleted file mode 100644 index 232d720dd897..000000000000 --- a/packages/auth-providers-web/webAuthn/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "./index.js", - "types": "../dist/dbAuth/webAuthn.d.ts" -} diff --git a/packages/auth-providers/auth0/api/package.json b/packages/auth-providers/auth0/api/package.json index e7b38da4e2d7..a829445c8b8b 100644 --- a/packages/auth-providers/auth0/api/package.json +++ b/packages/auth-providers/auth0/api/package.json @@ -30,12 +30,10 @@ "devDependencies": { "@babel/cli": "7.19.3", "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", "@types/jsonwebtoken": "8.5.9", "jest": "29.3.1", "typescript": "4.7.4" }, - "peerDependencies": { - "@redwoodjs/api": "3.2.0" - }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/auth0/api/tsconfig.json b/packages/auth-providers/auth0/api/tsconfig.json index a925964c5e44..bb9ec4a21fd1 100644 --- a/packages/auth-providers/auth0/api/tsconfig.json +++ b/packages/auth-providers/auth0/api/tsconfig.json @@ -8,5 +8,5 @@ "outDir": "dist" }, "include": ["src"], - "references": [{ "path": "../../../auth" }] + "references": [{ "path": "../../../api" }] } diff --git a/packages/auth-providers/auth0/setup/src/index.ts b/packages/auth-providers/auth0/setup/src/index.ts index c8688a8da674..5a774a6b36e2 100644 --- a/packages/auth-providers/auth0/setup/src/index.ts +++ b/packages/auth-providers/auth0/setup/src/index.ts @@ -1 +1 @@ -export * as setupAuthAuth0Command from './setup' +export * from './setup' diff --git a/packages/auth-providers/auth0/setup/src/setup.ts b/packages/auth-providers/auth0/setup/src/setup.ts index da394e2bd48b..fd72e3b46418 100644 --- a/packages/auth-providers/auth0/setup/src/setup.ts +++ b/packages/auth-providers/auth0/setup/src/setup.ts @@ -1,49 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'auth0' export const description = 'Generate an auth configuration for Auth0' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'auth0', - authDecoderImport: - "import { authDecoder } from '@redwoodjs/auth-auth0-api'", - apiPackages: ['@redwoodjs/auth-auth0-api'], - webPackages: ['@auth0/auth0-spa-js@1.22.5', '@redwoodjs/auth-auth0-web'], - notes: [ - 'You will need to create several environment variables with your Auth0 config options.', - 'Check out web/src/App.{js,tsx} for the variables you need to add.', - 'See: https://auth0.com/docs/quickstart/spa/react#get-your-application-keys', - '\n', - "You must also create an API and set the audience parameter, or you'll", - 'receive an opaque token instead of the required JWT token.', - 'See: https://auth0.com/docs/quickstart/spa/react/02-calling-an-api#create-an-api', - '\n', - 'If you want to allow users to get refresh tokens while offline,', - 'you must also enable the Allow Offline Access switch in your', - 'Auth0 API Settings as part of setup configuration.', - 'See: https://auth0.com/docs/tokens/refresh-tokens', - '\n', - 'You can increase security by using refresh token rotation which issues a new refresh token', - 'and invalidates the predecessor token with each request made to Auth0 for a new access token.', - 'Rotating the refresh token reduces the risk of a compromised refresh token.', - 'See: https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler.js') + return handler(options) } diff --git a/packages/auth-providers/auth0/setup/src/setupHandler.ts b/packages/auth-providers/auth0/setup/src/setupHandler.ts new file mode 100644 index 000000000000..b9974979f518 --- /dev/null +++ b/packages/auth-providers/auth0/setup/src/setupHandler.ts @@ -0,0 +1,44 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'auth0', + authDecoderImport: + "import { authDecoder } from '@redwoodjs/auth-auth0-api'", + apiPackages: [`@redwoodjs/auth-auth0-api@${version}`], + webPackages: [ + '@auth0/auth0-spa-js@1.22.5', + `@redwoodjs/auth-auth0-web@${version}`, + ], + notes: [ + 'You will need to create several environment variables with your Auth0 config options.', + 'Check out web/src/App.{js,tsx} for the variables you need to add.', + 'See: https://auth0.com/docs/quickstart/spa/react#get-your-application-keys', + '', + "You must also create an API and set the audience parameter, or you'll", + 'receive an opaque token instead of the required JWT token.', + 'See: https://auth0.com/docs/quickstart/spa/react/02-calling-an-api#create-an-api', + '', + 'If you want to allow users to get refresh tokens while offline,', + 'you must also enable the Allow Offline Access switch in your', + 'Auth0 API Settings as part of setup configuration.', + 'See: https://auth0.com/docs/tokens/refresh-tokens', + '', + 'You can increase security by using refresh token rotation which issues a new refresh token', + 'and invalidates the predecessor token with each request made to Auth0 for a new access token.', + 'Rotating the refresh token reduces the risk of a compromised refresh token.', + 'See: https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation', + ], + }) +} diff --git a/packages/auth-providers/auth0/setup/src/templates/web/auth.ts.template b/packages/auth-providers/auth0/setup/src/templates/web/auth.ts.template index aad0d9a5d22f..9fb634ca6aa5 100644 --- a/packages/auth-providers/auth0/setup/src/templates/web/auth.ts.template +++ b/packages/auth-providers/auth0/setup/src/templates/web/auth.ts.template @@ -1,6 +1,6 @@ import { Auth0Client } from '@auth0/auth0-spa-js' -import { createAuth0Auth } from '@redwoodjs/auth-providers-web' +import { createAuth0Auth } from '@redwoodjs/auth-auth0-web' const auth0 = new Auth0Client({ domain: process.env.AUTH0_DOMAIN || '', diff --git a/packages/auth-providers/auth0/web/package.json b/packages/auth-providers/auth0/web/package.json index b6c2439d3543..516aef5d62de 100644 --- a/packages/auth-providers/auth0/web/package.json +++ b/packages/auth-providers/auth0/web/package.json @@ -23,9 +23,11 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", "core-js": "3.26.1" }, "devDependencies": { + "@auth0/auth0-spa-js": "1.22.5", "@babel/cli": "7.19.3", "@babel/core": "7.20.5", "@testing-library/react-hooks": "8.0.1", @@ -35,8 +37,7 @@ "typescript": "4.7.4" }, "peerDependencies": { - "@auth0/auth0-spa-js": "1.22.5", - "@redwoodjs/auth": "3.2.0" + "@auth0/auth0-spa-js": "1.22.5" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/azureActiveDirectory/api/package.json b/packages/auth-providers/azureActiveDirectory/api/package.json index 9df765f91b7b..358e3e9ae601 100644 --- a/packages/auth-providers/azureActiveDirectory/api/package.json +++ b/packages/auth-providers/azureActiveDirectory/api/package.json @@ -24,17 +24,17 @@ "dependencies": { "@babel/runtime-corejs3": "7.20.6", "core-js": "3.26.1", - "jsonwebtoken": "8.5.1" + "jsonwebtoken": "8.5.1", + "jwks-rsa": "2.0.5" }, "devDependencies": { "@babel/cli": "7.19.3", "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", + "@types/aws-lambda": "8.10.107", "@types/jsonwebtoken": "8.5.9", "jest": "29.3.1", "typescript": "4.7.4" }, - "peerDependencies": { - "@redwoodjs/api": "3.2.0" - }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/azureActiveDirectory/api/tsconfig.json b/packages/auth-providers/azureActiveDirectory/api/tsconfig.json index a925964c5e44..bb9ec4a21fd1 100644 --- a/packages/auth-providers/azureActiveDirectory/api/tsconfig.json +++ b/packages/auth-providers/azureActiveDirectory/api/tsconfig.json @@ -8,5 +8,5 @@ "outDir": "dist" }, "include": ["src"], - "references": [{ "path": "../../../auth" }] + "references": [{ "path": "../../../api" }] } diff --git a/packages/auth-providers/azureActiveDirectory/setup/src/index.ts b/packages/auth-providers/azureActiveDirectory/setup/src/index.ts index f2cc0ebb8b77..5a774a6b36e2 100644 --- a/packages/auth-providers/azureActiveDirectory/setup/src/index.ts +++ b/packages/auth-providers/azureActiveDirectory/setup/src/index.ts @@ -1 +1 @@ -export * as setupAuthAzureActiveDirectoryCommand from './setup' +export * from './setup' diff --git a/packages/auth-providers/azureActiveDirectory/setup/src/setup.ts b/packages/auth-providers/azureActiveDirectory/setup/src/setup.ts index d548162f8f9d..9ea8411cd7e5 100644 --- a/packages/auth-providers/azureActiveDirectory/setup/src/setup.ts +++ b/packages/auth-providers/azureActiveDirectory/setup/src/setup.ts @@ -1,46 +1,20 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'azure-active-directory' export const description = 'Generate an auth configuration for Azure Active Directory' -export const builder = (yargs: yargs.Argv) => { +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'azureActiveDirectory', - authDecoderImport: - "import { authDecoder } from '@redwoodjs/auth-azure-active-directory-api'", - apiPackages: ['@redwoodjs/auth-azure-active-directory-api'], - webPackages: [ - '@redwoodjs/auth-azure-active-directory-web', - '@azure/msal-browser', - ], - notes: [ - 'You will need to create several environment variables with your Azure', - 'AD config options. Check out web/src/App.{js,tsx} for the variables', - 'you need to add.', - '\n', - 'RedwoodJS specific Documentation:', - 'https://redwoodjs.com/docs/authentication#azure-ad', - '\n', - 'MSAL.js Documentation:', - 'https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers/azureActiveDirectory/setup/src/setupHandler.ts b/packages/auth-providers/azureActiveDirectory/setup/src/setupHandler.ts new file mode 100644 index 000000000000..752dfd22eabe --- /dev/null +++ b/packages/auth-providers/azureActiveDirectory/setup/src/setupHandler.ts @@ -0,0 +1,36 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'azureActiveDirectory', + authDecoderImport: + "import { authDecoder } from '@redwoodjs/auth-azure-active-directory-api'", + apiPackages: [`@redwoodjs/auth-azure-active-directory-api@${version}`], + webPackages: [ + `@redwoodjs/auth-azure-active-directory-web@${version}`, + '@azure/msal-browser', + ], + notes: [ + 'You will need to create several environment variables with your Azure', + 'AD config options. Check out web/src/App.{js,tsx} for the variables', + 'you need to add.', + '\n', + 'RedwoodJS specific Documentation:', + 'https://redwoodjs.com/docs/authentication#azure-ad', + '\n', + 'MSAL.js Documentation:', + 'https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications', + ], + }) +} diff --git a/packages/auth-providers/azureActiveDirectory/setup/src/templates/web/auth.ts.template b/packages/auth-providers/azureActiveDirectory/setup/src/templates/web/auth.ts.template index 7a82261b2450..49128f89c65b 100644 --- a/packages/auth-providers/azureActiveDirectory/setup/src/templates/web/auth.ts.template +++ b/packages/auth-providers/azureActiveDirectory/setup/src/templates/web/auth.ts.template @@ -1,6 +1,6 @@ import { PublicClientApplication } from '@azure/msal-browser' -import { createAzureActiveDirectoryAuth } from '@redwoodjs/auth-providers-web' +import { createAzureActiveDirectoryAuth } from '@redwoodjs/azure-active-directory-web' const azureActiveDirectoryClient = new PublicClientApplication({ auth: { diff --git a/packages/auth-providers/azureActiveDirectory/web/package.json b/packages/auth-providers/azureActiveDirectory/web/package.json index db78ae662084..66d7728eaf50 100644 --- a/packages/auth-providers/azureActiveDirectory/web/package.json +++ b/packages/auth-providers/azureActiveDirectory/web/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", "core-js": "3.26.1" }, "devDependencies": { @@ -37,8 +38,7 @@ "typescript": "4.7.4" }, "peerDependencies": { - "@azure/msal-browser": "2.30.0", - "@redwoodjs/auth": "3.2.0" + "@azure/msal-browser": "2.30.0" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/clerk/api/.babelrc.js b/packages/auth-providers/clerk/api/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/clerk/api/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/clerk/api/README.md b/packages/auth-providers/clerk/api/README.md new file mode 100644 index 000000000000..d27ea3626dac --- /dev/null +++ b/packages/auth-providers/clerk/api/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider there's more info in the +[auth docs](https://redwoodjs.com/docs/authentication). + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/clerk/api/jest.config.js b/packages/auth-providers/clerk/api/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/clerk/api/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/clerk/api/package.json b/packages/auth-providers/clerk/api/package.json new file mode 100644 index 000000000000..7f4ff85e6b76 --- /dev/null +++ b/packages/auth-providers/clerk/api/package.json @@ -0,0 +1,38 @@ +{ + "name": "@redwoodjs/auth-clerk-api", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/clerk/api" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@clerk/clerk-sdk-node": "3.9.2", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", + "@types/aws-lambda": "8.10.107", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-api/src/clerk/__tests__/clerk.test.ts b/packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts similarity index 100% rename from packages/auth-providers-api/src/clerk/__tests__/clerk.test.ts rename to packages/auth-providers/clerk/api/src/__tests__/clerk.test.ts diff --git a/packages/auth-providers-api/src/clerk/decoder.ts b/packages/auth-providers/clerk/api/src/decoder.ts similarity index 77% rename from packages/auth-providers-api/src/clerk/decoder.ts rename to packages/auth-providers/clerk/api/src/decoder.ts index 0976b19d715c..82933a6470fe 100644 --- a/packages/auth-providers-api/src/clerk/decoder.ts +++ b/packages/auth-providers/clerk/api/src/decoder.ts @@ -5,16 +5,15 @@ export const authDecoder: Decoder = async (token: string, type: string) => { return null } - // Use require here, to prevent needing clerk sdk in api deps - const { users, base } = require('@clerk/clerk-sdk-node').default - if (!process.env.CLERK_JWT_KEY) { console.error('CLERK_JWT_KEY env var is not set.') throw new Error('CLERK_JWT_KEY env var is not set.') } + const { users, default: clerk } = await import('@clerk/clerk-sdk-node') + try { - const jwtPayload = await base.verifySessionToken(token) + const jwtPayload = await clerk.base.verifySessionToken(token) if (!jwtPayload.sub) { return Promise.reject(new Error('Session invalid')) diff --git a/packages/auth-providers/clerk/api/src/index.ts b/packages/auth-providers/clerk/api/src/index.ts new file mode 100644 index 000000000000..ead5bdde8676 --- /dev/null +++ b/packages/auth-providers/clerk/api/src/index.ts @@ -0,0 +1 @@ +export { authDecoder } from './decoder' diff --git a/packages/auth-providers/clerk/api/tsconfig.json b/packages/auth-providers/clerk/api/tsconfig.json new file mode 100644 index 000000000000..bb9ec4a21fd1 --- /dev/null +++ b/packages/auth-providers/clerk/api/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../api" }] +} diff --git a/packages/auth-providers/clerk/setup/.babelrc.js b/packages/auth-providers/clerk/setup/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/clerk/setup/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/clerk/setup/README.md b/packages/auth-providers/clerk/setup/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/clerk/setup/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/clerk/setup/jest.config.js b/packages/auth-providers/clerk/setup/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/clerk/setup/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/clerk/setup/package.json b/packages/auth-providers/clerk/setup/package.json new file mode 100644 index 000000000000..58df6e83bad4 --- /dev/null +++ b/packages/auth-providers/clerk/setup/package.json @@ -0,0 +1,37 @@ +{ + "name": "@redwoodjs/auth-clerk-setup", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/clerk/setup" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src --passWithNoTests", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/cli-helpers": "3.2.0", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@types/yargs": "17.0.13", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers/clerk/setup/src/index.ts b/packages/auth-providers/clerk/setup/src/index.ts new file mode 100644 index 000000000000..5a774a6b36e2 --- /dev/null +++ b/packages/auth-providers/clerk/setup/src/index.ts @@ -0,0 +1 @@ +export * from './setup' diff --git a/packages/auth-providers/clerk/setup/src/setup.ts b/packages/auth-providers/clerk/setup/src/setup.ts new file mode 100644 index 000000000000..f058a4722e2c --- /dev/null +++ b/packages/auth-providers/clerk/setup/src/setup.ts @@ -0,0 +1,19 @@ +import yargs from 'yargs' + +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' + +export const command = 'clerk' +export const description = 'Generate an auth configuration for Clerk' + +export function builder(yargs: yargs.Argv) { + return standardAuthBuilder(yargs) +} + +export interface Args { + force: boolean +} + +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) +} diff --git a/packages/auth-providers/clerk/setup/src/setupHandler.ts b/packages/auth-providers/clerk/setup/src/setupHandler.ts new file mode 100644 index 000000000000..a192f3b1fee5 --- /dev/null +++ b/packages/auth-providers/clerk/setup/src/setupHandler.ts @@ -0,0 +1,26 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export const handler = async ({ force: forceArg }: Args) => { + standardAuthHandler({ + basedir: __dirname, + forceArg, + authDecoderImport: `import { authDecoder } from '@redwoodjs/auth-clerk-api`, + provider: 'clerk', + webPackages: ['@clerk/clerk-react', `@redwoodjs/auth-clerk-web@${version}`], + apiPackages: [`@redwoodjs/auth-clerk-api@${version}`], + notes: [ + 'You will need to add three environment variables with your Clerk URL, API key and JWT key.', + 'Check out web/src/auth.{js,tsx} for the variables you need to add.', + 'See also: https://redwoodjs.com/docs/authentication#clerk', + ], + }) +} diff --git a/packages/auth-providers-setup/src/clerk/templates/api/lib/auth.ts.template b/packages/auth-providers/clerk/setup/src/templates/api/lib/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/clerk/templates/api/lib/auth.ts.template rename to packages/auth-providers/clerk/setup/src/templates/api/lib/auth.ts.template diff --git a/packages/auth-providers-setup/src/clerk/templates/web/auth.tsx.template b/packages/auth-providers/clerk/setup/src/templates/web/auth.tsx.template similarity index 95% rename from packages/auth-providers-setup/src/clerk/templates/web/auth.tsx.template rename to packages/auth-providers/clerk/setup/src/templates/web/auth.tsx.template index 6ee37378c849..1eb72ea5641f 100644 --- a/packages/auth-providers-setup/src/clerk/templates/web/auth.tsx.template +++ b/packages/auth-providers/clerk/setup/src/templates/web/auth.tsx.template @@ -2,7 +2,7 @@ import React, { useEffect } from 'react' import { ClerkLoaded, ClerkProvider, useUser } from '@clerk/clerk-react' -import { createClerkAuth } from '@redwoodjs/auth-providers-web' +import { createClerkAuth } from '@redwoodjs/auth-clerk-web' import { navigate } from '@redwoodjs/router' // You can set user roles in a "roles" array on the public metadata in Clerk. diff --git a/packages/auth-providers/clerk/setup/tsconfig.json b/packages/auth-providers/clerk/setup/tsconfig.json new file mode 100644 index 000000000000..abb54b70112a --- /dev/null +++ b/packages/auth-providers/clerk/setup/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../cli-helpers" }] +} diff --git a/packages/auth-providers/clerk/web/.babelrc.js b/packages/auth-providers/clerk/web/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/clerk/web/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/clerk/web/README.md b/packages/auth-providers/clerk/web/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/clerk/web/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/clerk/web/jest.config.js b/packages/auth-providers/clerk/web/jest.config.js new file mode 100644 index 000000000000..e691bb8f6dbd --- /dev/null +++ b/packages/auth-providers/clerk/web/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testEnvironment: 'jest-environment-jsdom', + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/clerk/web/package.json b/packages/auth-providers/clerk/web/package.json new file mode 100644 index 000000000000..49aced7e2c69 --- /dev/null +++ b/packages/auth-providers/clerk/web/package.json @@ -0,0 +1,44 @@ +{ + "name": "@redwoodjs/auth-clerk-web", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/clerk/web" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@clerk/clerk-react": "3.5.1", + "@clerk/types": "2.21.0", + "@testing-library/react-hooks": "8.0.1", + "@types/react": "17.0.50", + "jest": "29.3.1", + "react": "17.0.2", + "typescript": "4.7.4" + }, + "peerDependencies": { + "@clerk/clerk-react": "3.5.1" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-web/src/clerk/__tests__/clerk.test.tsx b/packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx similarity index 100% rename from packages/auth-providers-web/src/clerk/__tests__/clerk.test.tsx rename to packages/auth-providers/clerk/web/src/__tests__/clerk.test.tsx diff --git a/packages/auth-providers-web/src/clerk/clerk.tsx b/packages/auth-providers/clerk/web/src/clerk.tsx similarity index 100% rename from packages/auth-providers-web/src/clerk/clerk.tsx rename to packages/auth-providers/clerk/web/src/clerk.tsx diff --git a/packages/auth-providers/clerk/web/src/index.ts b/packages/auth-providers/clerk/web/src/index.ts new file mode 100644 index 000000000000..f99029608cc2 --- /dev/null +++ b/packages/auth-providers/clerk/web/src/index.ts @@ -0,0 +1 @@ +export { createClerkAuth } from './clerk' diff --git a/packages/auth-providers/clerk/web/tsconfig.json b/packages/auth-providers/clerk/web/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/clerk/web/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth-providers/custom/setup/src/index.ts b/packages/auth-providers/custom/setup/src/index.ts index e6ab4ba035b2..5a774a6b36e2 100644 --- a/packages/auth-providers/custom/setup/src/index.ts +++ b/packages/auth-providers/custom/setup/src/index.ts @@ -1 +1 @@ -export * as setupAuthCustomCommand from './setup' +export * from './setup' diff --git a/packages/auth-providers/custom/setup/src/setup.ts b/packages/auth-providers/custom/setup/src/setup.ts index 24786e26a9bc..ae8a986db91b 100644 --- a/packages/auth-providers/custom/setup/src/setup.ts +++ b/packages/auth-providers/custom/setup/src/setup.ts @@ -1,34 +1,19 @@ import yargs from 'yargs' -import { - isTypeScriptProject, - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'custom' export const description = 'Generate a custom auth configuration' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - const authFilename = isTypeScriptProject() ? 'auth.ts' : 'auth.js' - - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'custom', - notes: [ - 'Done! But you have a little more work to do:\n', - 'You will have to write the actual auth implementation/integration', - `yourself. Take a look in ${authFilename} and do the necessary changes.`, - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers/custom/setup/src/setupHandler.ts b/packages/auth-providers/custom/setup/src/setupHandler.ts new file mode 100644 index 000000000000..50460c80f00d --- /dev/null +++ b/packages/auth-providers/custom/setup/src/setupHandler.ts @@ -0,0 +1,29 @@ +import fs from 'fs' +import path from 'path' + +import { + isTypeScriptProject, + standardAuthHandler, +} from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + const authFilename = isTypeScriptProject() ? 'auth.ts' : 'auth.js' + + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'custom', + webPackages: [`@redwoodjs/auth@${version}`], + notes: [ + 'Done! But you have a little more work to do:\n', + 'You will have to write the actual auth implementation/integration', + `yourself. Take a look in ${authFilename} and do the necessary changes.`, + ], + }) +} diff --git a/packages/auth-providers/dbAuth/api/.babelrc.js b/packages/auth-providers/dbAuth/api/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/dbAuth/api/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/dbAuth/api/README.md b/packages/auth-providers/dbAuth/api/README.md new file mode 100644 index 000000000000..d27ea3626dac --- /dev/null +++ b/packages/auth-providers/dbAuth/api/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider there's more info in the +[auth docs](https://redwoodjs.com/docs/authentication). + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/dbAuth/api/jest.config.js b/packages/auth-providers/dbAuth/api/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/dbAuth/api/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/dbAuth/api/package.json b/packages/auth-providers/dbAuth/api/package.json new file mode 100644 index 000000000000..c05cb310e482 --- /dev/null +++ b/packages/auth-providers/dbAuth/api/package.json @@ -0,0 +1,43 @@ +{ + "name": "@redwoodjs/auth-dbauth-api", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/dbAuth/api" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "base64url": "3.0.1", + "core-js": "3.26.1", + "crypto-js": "4.1.1", + "md5": "2.3.0", + "uuid": "9.0.0" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", + "@types/crypto-js": "4.1.1", + "@types/md5": "2.3.2", + "@types/uuid": "8.3.4", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-api/src/dbAuth/DbAuthHandler.ts b/packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts similarity index 100% rename from packages/auth-providers-api/src/dbAuth/DbAuthHandler.ts rename to packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts diff --git a/packages/auth-providers-api/src/dbAuth/__tests__/DbAuthHandler.test.js b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js similarity index 99% rename from packages/auth-providers-api/src/dbAuth/__tests__/DbAuthHandler.test.js rename to packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js index b173d0bae686..56623467d51f 100644 --- a/packages/auth-providers-api/src/dbAuth/__tests__/DbAuthHandler.test.js +++ b/packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.test.js @@ -1,8 +1,3 @@ -/** - * TODO: Get rid of this when dbAuth/api is its own package - * @jest-environment node - */ - import CryptoJS from 'crypto-js' import { DbAuthHandler } from '../DbAuthHandler' diff --git a/packages/auth-providers-api/src/dbAuth/__tests__/shared.test.js b/packages/auth-providers/dbAuth/api/src/__tests__/shared.test.js similarity index 100% rename from packages/auth-providers-api/src/dbAuth/__tests__/shared.test.js rename to packages/auth-providers/dbAuth/api/src/__tests__/shared.test.js diff --git a/packages/auth-providers-api/src/dbAuth/decoder.ts b/packages/auth-providers/dbAuth/api/src/decoder.ts similarity index 100% rename from packages/auth-providers-api/src/dbAuth/decoder.ts rename to packages/auth-providers/dbAuth/api/src/decoder.ts diff --git a/packages/auth-providers-api/src/dbAuth/errors.ts b/packages/auth-providers/dbAuth/api/src/errors.ts similarity index 100% rename from packages/auth-providers-api/src/dbAuth/errors.ts rename to packages/auth-providers/dbAuth/api/src/errors.ts diff --git a/packages/auth-providers-api/src/dbAuth/index.ts b/packages/auth-providers/dbAuth/api/src/index.ts similarity index 72% rename from packages/auth-providers-api/src/dbAuth/index.ts rename to packages/auth-providers/dbAuth/api/src/index.ts index 04c5a2661947..129130bbef63 100644 --- a/packages/auth-providers-api/src/dbAuth/index.ts +++ b/packages/auth-providers/dbAuth/api/src/index.ts @@ -1,3 +1,4 @@ export * from './DbAuthHandler' export { PasswordValidationError } from './errors' export * from './shared' +export { authDecoder } from './decoder' diff --git a/packages/auth-providers-api/src/dbAuth/shared.ts b/packages/auth-providers/dbAuth/api/src/shared.ts similarity index 100% rename from packages/auth-providers-api/src/dbAuth/shared.ts rename to packages/auth-providers/dbAuth/api/src/shared.ts diff --git a/packages/auth-providers/dbAuth/api/tsconfig.json b/packages/auth-providers/dbAuth/api/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/dbAuth/api/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth-providers/dbAuth/setup/.babelrc.js b/packages/auth-providers/dbAuth/setup/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/dbAuth/setup/README.md b/packages/auth-providers/dbAuth/setup/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/dbAuth/setup/jest.config.js b/packages/auth-providers/dbAuth/setup/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/dbAuth/setup/package.json b/packages/auth-providers/dbAuth/setup/package.json new file mode 100644 index 000000000000..8ed673095f7a --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/package.json @@ -0,0 +1,43 @@ +{ + "name": "@redwoodjs/auth-dbauth-setup", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/dbAuth/setup" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src --passWithNoTests", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/cli-helpers": "3.2.0", + "@simplewebauthn/browser": "6.2.1", + "core-js": "3.26.1", + "prompts": "2.4.2", + "secure-random-password": "0.2.3", + "terminal-link": "2.1.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@simplewebauthn/typescript-types": "6.2.1", + "@types/secure-random-password": "0.2.1", + "@types/yargs": "17.0.13", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers/dbAuth/setup/src/index.ts b/packages/auth-providers/dbAuth/setup/src/index.ts new file mode 100644 index 000000000000..5a774a6b36e2 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/src/index.ts @@ -0,0 +1 @@ +export * from './setup' diff --git a/packages/auth-providers/dbAuth/setup/src/setup.ts b/packages/auth-providers/dbAuth/setup/src/setup.ts new file mode 100644 index 000000000000..02451e82bbc9 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/src/setup.ts @@ -0,0 +1,42 @@ +import terminalLink from 'terminal-link' +import yargs from 'yargs' + +export const command = 'dbAuth' +export const description = 'Generate an auth configuration for dbAuth' + +export function builder(yargs: yargs.Argv) { + yargs + .option('warn', { + default: true, + description: 'Experimental auth warning', + type: 'boolean', + }) + .option('force', { + alias: 'f', + default: false, + description: 'Overwrite existing configuration', + type: 'boolean', + }) + .option('webauthn', { + alias: 'w', + default: null, + description: 'Include WebAuthn support (TouchID/FaceID)', + type: 'boolean', + }) + .epilogue( + `Also see the ${terminalLink( + 'Redwood CLI Reference', + 'https://redwoodjs.com/docs/cli-commands#setup-auth' + )}` + ) +} + +export interface Args { + webauthn: boolean + force: boolean +} + +export const handler = async (options: Args) => { + const { handler } = await import('./setupHandler') + return handler(options) +} diff --git a/packages/auth-providers-setup/src/dbAuth/setupData.ts b/packages/auth-providers/dbAuth/setup/src/setupData.ts similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/setupData.ts rename to packages/auth-providers/dbAuth/setup/src/setupData.ts diff --git a/packages/auth-providers-setup/src/dbAuth/setup.ts b/packages/auth-providers/dbAuth/setup/src/setupHandler.ts similarity index 50% rename from packages/auth-providers-setup/src/dbAuth/setup.ts rename to packages/auth-providers/dbAuth/setup/src/setupHandler.ts index a08243ded810..bc0fd317877c 100644 --- a/packages/auth-providers-setup/src/dbAuth/setup.ts +++ b/packages/auth-providers/dbAuth/setup/src/setupHandler.ts @@ -1,9 +1,11 @@ +import fs from 'fs' +import path from 'path' + import prompts from 'prompts' -import terminalLink from 'terminal-link' -import yargs from 'yargs' import { standardAuthHandler } from '@redwoodjs/cli-helpers' +import { Args } from './setup' import { notes, extraTask } from './setupData' import { notes as webAuthnNotes, @@ -12,6 +14,31 @@ import { apiPackages as webAuthnApiPackages, } from './webAuthn.setupData' +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ webauthn, force: forceArg }: Args) { + const webAuthn = await shouldIncludeWebAuthn(webauthn) + + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'dbAuth', + authDecoderImport: + "import { authDecoder } from '@redwoodjs/auth-dbauth-api'", + webAuthn, + webPackages: webAuthn + ? webAuthnWebPackages + : [`@redwoodjs/auth-dbauth-web@${version}`], + apiPackages: webAuthn + ? webAuthnApiPackages + : [`@redwoodjs/auth-dbauth-api@${version}`], + extraTask: webAuthn ? webAuthnExtraTask : extraTask, + notes: webAuthn ? webAuthnNotes : notes, + }) +} + /** * Prompt the user (unless already specified on the command line) if they want * to enable WebAuthn support @@ -30,64 +57,3 @@ async function shouldIncludeWebAuthn(webauthn: boolean) { return webauthn } - -export const command = 'dbAuth' -export const description = 'Generate an auth configuration for dbAuth' -export const builder = (yargs: yargs.Argv) => { - yargs - .option('warn', { - default: true, - description: 'Experimental auth warning', - type: 'boolean', - }) - .option('force', { - alias: 'f', - default: false, - description: 'Overwrite existing configuration', - type: 'boolean', - }) - .option('webauthn', { - alias: 'w', - default: null, - description: 'Include WebAuthn support (TouchID/FaceID)', - type: 'boolean', - }) - .epilogue( - `Also see the ${terminalLink( - 'Redwood CLI Reference', - 'https://redwoodjs.com/docs/cli-commands#setup-auth' - )}` - ) -} - -interface Args { - rwVersion: string - webauthn: boolean - force: boolean -} - -export const handler = async ({ - rwVersion, - webauthn, - force: forceArg, -}: Args) => { - const webAuthn = await shouldIncludeWebAuthn(webauthn) - - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'dbAuth', - authDecoderImport: - "import { dbAuthAuthDecoder as authDecoder } from '@redwoodjs/auth-providers-api'", - webAuthn, - webPackages: webAuthn - ? webAuthnWebPackages - : ['@redwoodjs/auth-providers-web'], - apiPackages: webAuthn - ? webAuthnApiPackages - : ['@redwoodjs/auth-providers-api'], - extraTask: webAuthn ? webAuthnExtraTask : extraTask, - notes: webAuthn ? webAuthnNotes : notes, - }) -} diff --git a/packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.ts.template similarity index 99% rename from packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.ts.template rename to packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.ts.template index 45d79d800341..f8d8e2cd4e70 100644 --- a/packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.ts.template +++ b/packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.ts.template @@ -1,6 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda' -import { DbAuthHandler, DbAuthHandlerOptions } from '@redwoodjs/auth-providers-api' +import { DbAuthHandler, DbAuthHandlerOptions } from '@redwoodjs/auth-dbauth-api' import { db } from 'src/lib/db' diff --git a/packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.webAuthn.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.webAuthn.ts.template similarity index 99% rename from packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.webAuthn.ts.template rename to packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.webAuthn.ts.template index d2836bcc5361..117a85726ec9 100644 --- a/packages/auth-providers-setup/src/dbAuth/templates/api/functions/auth.webAuthn.ts.template +++ b/packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.webAuthn.ts.template @@ -1,6 +1,6 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda' -import { DbAuthHandler, DbAuthHandlerOptions } from '@redwoodjs/auth-providers-api' +import { DbAuthHandler, DbAuthHandlerOptions } from '@redwoodjs/auth-dbauth-api' import { db } from 'src/lib/db' diff --git a/packages/auth-providers-setup/src/dbAuth/templates/api/lib/auth.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/api/lib/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/templates/api/lib/auth.ts.template rename to packages/auth-providers/dbAuth/setup/src/templates/api/lib/auth.ts.template diff --git a/packages/auth-providers/dbAuth/setup/src/templates/web/auth.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.ts.template new file mode 100644 index 000000000000..4a620e5ecf37 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.ts.template @@ -0,0 +1,3 @@ +import { createDbAuth } from '@redwoodjs/auth-dbauth-web' + +export const { AuthProvider, useAuth } = createDbAuth() diff --git a/packages/auth-providers/dbAuth/setup/src/templates/web/auth.webAuthn.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.webAuthn.ts.template new file mode 100644 index 000000000000..2195ffbe4dac --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.webAuthn.ts.template @@ -0,0 +1,4 @@ +import { createDbAuth } from '@redwoodjs/auth-dbauth-web' +import WebAuthnClient from '@redwoodjs/@redwoodjs/auth-dbauth-web/webAuthn' + +export const { AuthProvider, useAuth } = createDbAuth(WebAuthnClient) diff --git a/packages/auth-providers-setup/src/dbAuth/webAuthn.setupData.ts b/packages/auth-providers/dbAuth/setup/src/webAuthn.setupData.ts similarity index 98% rename from packages/auth-providers-setup/src/dbAuth/webAuthn.setupData.ts rename to packages/auth-providers/dbAuth/setup/src/webAuthn.setupData.ts index 0aceb9e06803..12718a06cb4a 100644 --- a/packages/auth-providers-setup/src/dbAuth/webAuthn.setupData.ts +++ b/packages/auth-providers/dbAuth/setup/src/webAuthn.setupData.ts @@ -9,13 +9,13 @@ export { extraTask } from './setupData' // required packages to install on the web side export const webPackages = [ - '@redwoodjs/auth-providers-web', + '@redwoodjs/auth-dbauth-web', '@simplewebauthn/browser', ] // required packages to install on the api side export const apiPackages = [ - '@redwoodjs/auth-providers-api', + '@redwoodjs/auth-dbauth-api', '@simplewebauthn/server', ] diff --git a/packages/auth-providers/dbAuth/setup/tsconfig.json b/packages/auth-providers/dbAuth/setup/tsconfig.json new file mode 100644 index 000000000000..abb54b70112a --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../cli-helpers" }] +} diff --git a/packages/auth-providers/dbAuth/web/.babelrc.js b/packages/auth-providers/dbAuth/web/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/dbAuth/web/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/dbAuth/web/README.md b/packages/auth-providers/dbAuth/web/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/dbAuth/web/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/dbAuth/web/jest.config.js b/packages/auth-providers/dbAuth/web/jest.config.js new file mode 100644 index 000000000000..e691bb8f6dbd --- /dev/null +++ b/packages/auth-providers/dbAuth/web/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testEnvironment: 'jest-environment-jsdom', + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/dbAuth/web/package.json b/packages/auth-providers/dbAuth/web/package.json new file mode 100644 index 000000000000..406a60eb52da --- /dev/null +++ b/packages/auth-providers/dbAuth/web/package.json @@ -0,0 +1,42 @@ +{ + "name": "@redwoodjs/auth-dbauth-web", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/dbAuth/web" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist", + "webAuthn" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", + "@simplewebauthn/browser": "6.2.1", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@simplewebauthn/typescript-types": "6.2.1", + "@testing-library/react-hooks": "8.0.1", + "@types/react": "17.0.50", + "jest": "29.3.1", + "react": "17.0.2", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-web/src/dbAuth/__tests__/dbAuth.test.tsx b/packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.tsx similarity index 100% rename from packages/auth-providers-web/src/dbAuth/__tests__/dbAuth.test.tsx rename to packages/auth-providers/dbAuth/web/src/__tests__/dbAuth.test.tsx diff --git a/packages/auth-providers-web/src/dbAuth/dbAuth.ts b/packages/auth-providers/dbAuth/web/src/dbAuth.ts similarity index 100% rename from packages/auth-providers-web/src/dbAuth/dbAuth.ts rename to packages/auth-providers/dbAuth/web/src/dbAuth.ts diff --git a/packages/auth-providers/dbAuth/web/src/index.ts b/packages/auth-providers/dbAuth/web/src/index.ts new file mode 100644 index 000000000000..1cd8657f64b4 --- /dev/null +++ b/packages/auth-providers/dbAuth/web/src/index.ts @@ -0,0 +1 @@ +export { createDbAuth } from './dbAuth' diff --git a/packages/auth-providers-web/src/dbAuth/webAuthn.ts b/packages/auth-providers/dbAuth/web/src/webAuthn.ts similarity index 100% rename from packages/auth-providers-web/src/dbAuth/webAuthn.ts rename to packages/auth-providers/dbAuth/web/src/webAuthn.ts diff --git a/packages/auth-providers/dbAuth/web/tsconfig.json b/packages/auth-providers/dbAuth/web/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/dbAuth/web/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth-providers/dbAuth/web/webAuthn/index.js b/packages/auth-providers/dbAuth/web/webAuthn/index.js new file mode 100644 index 000000000000..3fb1caeaf8a5 --- /dev/null +++ b/packages/auth-providers/dbAuth/web/webAuthn/index.js @@ -0,0 +1,2 @@ +/* eslint-env es6, commonjs */ +module.exports = require('../dist/webAuthn') diff --git a/packages/auth-providers/dbAuth/web/webAuthn/package.json b/packages/auth-providers/dbAuth/web/webAuthn/package.json new file mode 100644 index 000000000000..e209f8931939 --- /dev/null +++ b/packages/auth-providers/dbAuth/web/webAuthn/package.json @@ -0,0 +1,4 @@ +{ + "main": "./index.js", + "types": "../dist/webAuthn.d.ts" +} diff --git a/packages/auth-providers/firebase/api/package.json b/packages/auth-providers/firebase/api/package.json index 0d92fd68f41c..c76166c47b1b 100644 --- a/packages/auth-providers/firebase/api/package.json +++ b/packages/auth-providers/firebase/api/package.json @@ -29,12 +29,10 @@ "devDependencies": { "@babel/cli": "7.19.3", "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", "@types/aws-lambda": "8.10.107", "jest": "29.3.1", "typescript": "4.7.4" }, - "peerDependencies": { - "@redwoodjs/api": "3.2.0" - }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts b/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts index 0a4242e4c8aa..f65556edf46e 100644 --- a/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts +++ b/packages/auth-providers/firebase/api/src/__tests__/firebase.test.ts @@ -1,11 +1,11 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda' -import * as firebaseAdmin from 'firebase-admin' +import admin from 'firebase-admin' import { authDecoder } from '../decoder' const verifyIdToken = jest.fn() -jest.spyOn(firebaseAdmin, 'auth').mockImplementation((() => { +jest.spyOn(admin, 'auth').mockImplementation((() => { return { verifyIdToken, } diff --git a/packages/auth-providers/firebase/api/src/decoder.ts b/packages/auth-providers/firebase/api/src/decoder.ts index cf00d26c9b80..83ed62b6fbed 100644 --- a/packages/auth-providers/firebase/api/src/decoder.ts +++ b/packages/auth-providers/firebase/api/src/decoder.ts @@ -1,3 +1,5 @@ +import admin from 'firebase-admin' + import { Decoder } from '@redwoodjs/api' export const authDecoder: Decoder = async (token: string, type: string) => { @@ -5,9 +7,6 @@ export const authDecoder: Decoder = async (token: string, type: string) => { return null } - // Use require here to prevent dependency for non-firebase projects - const admin = require('firebase-admin') - return admin.auth().verifyIdToken(token) // Alternative third-party JWT verification process described here: // https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library diff --git a/packages/auth-providers/firebase/api/tsconfig.json b/packages/auth-providers/firebase/api/tsconfig.json index a925964c5e44..bb9ec4a21fd1 100644 --- a/packages/auth-providers/firebase/api/tsconfig.json +++ b/packages/auth-providers/firebase/api/tsconfig.json @@ -8,5 +8,5 @@ "outDir": "dist" }, "include": ["src"], - "references": [{ "path": "../../../auth" }] + "references": [{ "path": "../../../api" }] } diff --git a/packages/auth-providers/firebase/setup/src/index.ts b/packages/auth-providers/firebase/setup/src/index.ts index e924f0f290ea..5a774a6b36e2 100644 --- a/packages/auth-providers/firebase/setup/src/index.ts +++ b/packages/auth-providers/firebase/setup/src/index.ts @@ -1 +1 @@ -export * as setupAuthFirebaseCommand from './setup' +export * from './setup' diff --git a/packages/auth-providers/firebase/setup/src/setup.ts b/packages/auth-providers/firebase/setup/src/setup.ts index b4230b56e4f5..3aa466f94c48 100644 --- a/packages/auth-providers/firebase/setup/src/setup.ts +++ b/packages/auth-providers/firebase/setup/src/setup.ts @@ -1,35 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'firebase' export const description = 'Generate an auth configuration for Firebase' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'firebase', - authDecoderImport: - "import { authDecoder } from '@redwoodjs/auth-firebase-api'", - webPackages: ['firebase', '@redwoodjs/auth-firebase-web'], - apiPackages: ['firebase-admin', '@redwoodjs/auth-firebase-api'], - notes: [ - 'You will need to create several environment variables with your Firebase config options.', - 'Check out web/src/auth.{js,ts} for the variables you need to add.', - 'See: https://firebase.google.com/docs/web/setup#config-object', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers/firebase/setup/src/setupHandler.ts b/packages/auth-providers/firebase/setup/src/setupHandler.ts new file mode 100644 index 000000000000..e1efd3d2859f --- /dev/null +++ b/packages/auth-providers/firebase/setup/src/setupHandler.ts @@ -0,0 +1,27 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'firebase', + authDecoderImport: + "import { authDecoder } from '@redwoodjs/auth-firebase-api'", + webPackages: ['firebase', `@redwoodjs/auth-firebase-web@${version}`], + apiPackages: ['firebase-admin', `@redwoodjs/auth-firebase-api@${version}`], + notes: [ + 'You will need to create several environment variables with your Firebase config options.', + 'Check out web/src/auth.{js,ts} for the variables you need to add.', + 'See: https://firebase.google.com/docs/web/setup#config-object', + ], + }) +} diff --git a/packages/auth-providers/firebase/setup/src/templates/web/auth.ts.template b/packages/auth-providers/firebase/setup/src/templates/web/auth.ts.template index 7f929c9df01d..1701b5ab0fb9 100644 --- a/packages/auth-providers/firebase/setup/src/templates/web/auth.ts.template +++ b/packages/auth-providers/firebase/setup/src/templates/web/auth.ts.template @@ -1,7 +1,7 @@ -import * as firebaseAuth from '@firebase/auth' +import * as firebaseAuth from 'firebase/auth' import { initializeApp, getApp, getApps } from 'firebase/app' -import { createFirebaseAuth } from '@redwoodjs/auth-providers-web' +import { createFirebaseAuth } from '@redwoodjs/auth-firebase-web' const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, diff --git a/packages/auth-providers/firebase/web/package.json b/packages/auth-providers/firebase/web/package.json index 9999fa884822..b85f564068bd 100644 --- a/packages/auth-providers/firebase/web/package.json +++ b/packages/auth-providers/firebase/web/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", "core-js": "3.26.1" }, "devDependencies": { @@ -36,7 +37,6 @@ "typescript": "4.7.4" }, "peerDependencies": { - "@redwoodjs/auth": "3.2.0", "firebase": "9.10.0" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers/netlify/api/package.json b/packages/auth-providers/netlify/api/package.json index d4b5c495cc9f..63b80df58817 100644 --- a/packages/auth-providers/netlify/api/package.json +++ b/packages/auth-providers/netlify/api/package.json @@ -29,13 +29,11 @@ "devDependencies": { "@babel/cli": "7.19.3", "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", "@types/aws-lambda": "8.10.107", "@types/jsonwebtoken": "8.5.9", "jest": "29.3.1", "typescript": "4.7.4" }, - "peerDependencies": { - "@redwoodjs/api": "3.2.0" - }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" } diff --git a/packages/auth-providers/netlify/api/tsconfig.json b/packages/auth-providers/netlify/api/tsconfig.json index a925964c5e44..bb9ec4a21fd1 100644 --- a/packages/auth-providers/netlify/api/tsconfig.json +++ b/packages/auth-providers/netlify/api/tsconfig.json @@ -8,5 +8,5 @@ "outDir": "dist" }, "include": ["src"], - "references": [{ "path": "../../../auth" }] + "references": [{ "path": "../../../api" }] } diff --git a/packages/auth-providers/netlify/setup/src/index.ts b/packages/auth-providers/netlify/setup/src/index.ts index 32c58bfa27c9..5a774a6b36e2 100644 --- a/packages/auth-providers/netlify/setup/src/index.ts +++ b/packages/auth-providers/netlify/setup/src/index.ts @@ -1 +1 @@ -export * as setupAuthNetlifyCommand from './setup' +export * from './setup' diff --git a/packages/auth-providers/netlify/setup/src/setup.ts b/packages/auth-providers/netlify/setup/src/setup.ts index 98b9f8ea1775..8dd0feb256d3 100644 --- a/packages/auth-providers/netlify/setup/src/setup.ts +++ b/packages/auth-providers/netlify/setup/src/setup.ts @@ -1,38 +1,19 @@ import yargs from 'yargs' -import { - standardAuthBuilder, - standardAuthHandler, -} from '@redwoodjs/cli-helpers' +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' export const command = 'netlify' export const description = 'Generate an auth configuration for Netlify' -export const builder = (yargs: yargs.Argv) => { + +export function builder(yargs: yargs.Argv) { return standardAuthBuilder(yargs) } -interface Args { - rwVersion: string +export interface Args { force: boolean } -export const handler = async ({ rwVersion, force: forceArg }: Args) => { - standardAuthHandler({ - basedir: __dirname, - rwVersion, - forceArg, - provider: 'netlify', - authDecoderImport: - "import { authDecoder } from '@redwoodjs/auth-netlify-api'", - apiPackages: ['@redwoodjs/auth-netlify-api'], - webPackages: [ - '@redwoodjs/auth-netlify-web', - 'netlify-identity-widget@1.9.2', - '@types/netlify-identity-widget', - ], - notes: [ - 'You will need to enable Identity on your Netlify site and configure the API endpoint.', - 'See: https://github.com/netlify/netlify-identity-widget#localhost', - ], - }) +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) } diff --git a/packages/auth-providers/netlify/setup/src/setupHandler.ts b/packages/auth-providers/netlify/setup/src/setupHandler.ts new file mode 100644 index 000000000000..bfe4aa0c2dcb --- /dev/null +++ b/packages/auth-providers/netlify/setup/src/setupHandler.ts @@ -0,0 +1,28 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'netlify', + authDecoderImport: `import { authDecoder } from '@redwoodjs/auth-netlify-api@${version}'`, + apiPackages: [`@redwoodjs/auth-netlify-api@${version}`], + webPackages: [ + `@redwoodjs/auth-netlify-web@${version}`, + 'netlify-identity-widget@1.9.2', + ], + notes: [ + 'You will need to enable Identity on your Netlify site and configure the API endpoint.', + 'See: https://github.com/netlify/netlify-identity-widget#localhost', + ], + }) +} diff --git a/packages/auth-providers/netlify/setup/src/templates/web/auth.ts.template b/packages/auth-providers/netlify/setup/src/templates/web/auth.ts.template index d220dbc09ae2..619f1aafd92b 100644 --- a/packages/auth-providers/netlify/setup/src/templates/web/auth.ts.template +++ b/packages/auth-providers/netlify/setup/src/templates/web/auth.ts.template @@ -1,6 +1,6 @@ import netlifyIdentity from 'netlify-identity-widget' -import { createNetlifyAuth } from '@redwoodjs/auth-providers-web' +import { createNetlifyAuth } from '@redwoodjs/auth-netlify-web' import { isBrowser } from '@redwoodjs/prerender/browserUtils' isBrowser && netlifyIdentity.init() diff --git a/packages/auth-providers/netlify/web/package.json b/packages/auth-providers/netlify/web/package.json index 2b55a9c55930..ef1a1966166c 100644 --- a/packages/auth-providers/netlify/web/package.json +++ b/packages/auth-providers/netlify/web/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", "core-js": "3.26.1" }, "devDependencies": { @@ -36,7 +37,6 @@ "typescript": "4.7.4" }, "peerDependencies": { - "@redwoodjs/auth": "3.2.0", "netlify-identity-widget": "1.9.2" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/auth-providers/supabase/api/.babelrc.js b/packages/auth-providers/supabase/api/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supabase/api/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supabase/api/README.md b/packages/auth-providers/supabase/api/README.md new file mode 100644 index 000000000000..d27ea3626dac --- /dev/null +++ b/packages/auth-providers/supabase/api/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider there's more info in the +[auth docs](https://redwoodjs.com/docs/authentication). + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supabase/api/jest.config.js b/packages/auth-providers/supabase/api/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/supabase/api/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supabase/api/package.json b/packages/auth-providers/supabase/api/package.json new file mode 100644 index 000000000000..06dc2c0c828a --- /dev/null +++ b/packages/auth-providers/supabase/api/package.json @@ -0,0 +1,39 @@ +{ + "name": "@redwoodjs/auth-supabase-api", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supabase/api" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "core-js": "3.26.1", + "jsonwebtoken": "8.5.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", + "@types/aws-lambda": "8.10.107", + "@types/jsonwebtoken": "8.5.9", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-api/src/supabase/__tests__/supabase.test.ts b/packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts similarity index 100% rename from packages/auth-providers-api/src/supabase/__tests__/supabase.test.ts rename to packages/auth-providers/supabase/api/src/__tests__/supabase.test.ts diff --git a/packages/auth-providers-api/src/supabase/decoder.ts b/packages/auth-providers/supabase/api/src/decoder.ts similarity index 100% rename from packages/auth-providers-api/src/supabase/decoder.ts rename to packages/auth-providers/supabase/api/src/decoder.ts diff --git a/packages/auth-providers/supabase/api/src/index.ts b/packages/auth-providers/supabase/api/src/index.ts new file mode 100644 index 000000000000..ead5bdde8676 --- /dev/null +++ b/packages/auth-providers/supabase/api/src/index.ts @@ -0,0 +1 @@ +export { authDecoder } from './decoder' diff --git a/packages/auth-providers/supabase/api/tsconfig.json b/packages/auth-providers/supabase/api/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/supabase/api/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth-providers/supabase/setup/.babelrc.js b/packages/auth-providers/supabase/setup/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supabase/setup/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supabase/setup/README.md b/packages/auth-providers/supabase/setup/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/supabase/setup/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supabase/setup/jest.config.js b/packages/auth-providers/supabase/setup/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/supabase/setup/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supabase/setup/package.json b/packages/auth-providers/supabase/setup/package.json new file mode 100644 index 000000000000..9590e0d45d13 --- /dev/null +++ b/packages/auth-providers/supabase/setup/package.json @@ -0,0 +1,37 @@ +{ + "name": "@redwoodjs/auth-supabase-setup", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supabase/setup" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src --passWithNoTests", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/cli-helpers": "3.2.0", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@types/yargs": "17.0.13", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers/supabase/setup/src/index.ts b/packages/auth-providers/supabase/setup/src/index.ts new file mode 100644 index 000000000000..5a774a6b36e2 --- /dev/null +++ b/packages/auth-providers/supabase/setup/src/index.ts @@ -0,0 +1 @@ +export * from './setup' diff --git a/packages/auth-providers/supabase/setup/src/setup.ts b/packages/auth-providers/supabase/setup/src/setup.ts new file mode 100644 index 000000000000..84f580ff84a4 --- /dev/null +++ b/packages/auth-providers/supabase/setup/src/setup.ts @@ -0,0 +1,19 @@ +import yargs from 'yargs' + +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' + +export const command = 'supabase' +export const description = 'Generate an auth configuration for Supabase' + +export function builder(yargs: yargs.Argv) { + return standardAuthBuilder(yargs) +} + +export interface Args { + force: boolean +} + +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) +} diff --git a/packages/auth-providers/supabase/setup/src/setupHandler.ts b/packages/auth-providers/supabase/setup/src/setupHandler.ts new file mode 100644 index 000000000000..82fec351a928 --- /dev/null +++ b/packages/auth-providers/supabase/setup/src/setupHandler.ts @@ -0,0 +1,29 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export const handler = async ({ force: forceArg }: Args) => { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'supabase', + authDecoderImport: `import { authDecoder } from '@redwoodjs/auth-supabase-api@${version}'`, + apiPackages: [`@redwoodjs/auth-providers-api@${version}`], + webPackages: [ + `@redwoodjs/auth-providers-web@${version}`, + '@supabase/supabase-js@1.35.7', + ], + notes: [ + 'You will need to add your Supabase URL (SUPABASE_URL), public API KEY,', + 'and JWT SECRET (SUPABASE_KEY, and SUPABASE_JWT_SECRET) to your .env file.', + 'See: https://supabase.io/docs/library/getting-started#reference', + ], + }) +} diff --git a/packages/auth-providers-setup/src/supabase/templates/api/lib/auth.ts.template b/packages/auth-providers/supabase/setup/src/templates/api/lib/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/supabase/templates/api/lib/auth.ts.template rename to packages/auth-providers/supabase/setup/src/templates/api/lib/auth.ts.template diff --git a/packages/auth-providers-setup/src/supabase/templates/web/auth.ts.template b/packages/auth-providers/supabase/setup/src/templates/web/auth.ts.template similarity index 78% rename from packages/auth-providers-setup/src/supabase/templates/web/auth.ts.template rename to packages/auth-providers/supabase/setup/src/templates/web/auth.ts.template index 67eaf850faa4..96afb8bd454f 100644 --- a/packages/auth-providers-setup/src/supabase/templates/web/auth.ts.template +++ b/packages/auth-providers/supabase/setup/src/templates/web/auth.ts.template @@ -1,6 +1,6 @@ import { createClient } from '@supabase/supabase-js' -import { createSupabaseAuth } from '@redwoodjs/auth-providers-web' +import { createSupabaseAuth } from '@redwoodjs/auth-supabase-web' const supabaseClient = createClient( process.env.SUPABASE_URL || '', diff --git a/packages/auth-providers/supabase/setup/tsconfig.json b/packages/auth-providers/supabase/setup/tsconfig.json new file mode 100644 index 000000000000..abb54b70112a --- /dev/null +++ b/packages/auth-providers/supabase/setup/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../cli-helpers" }] +} diff --git a/packages/auth-providers/supabase/web/.babelrc.js b/packages/auth-providers/supabase/web/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supabase/web/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supabase/web/README.md b/packages/auth-providers/supabase/web/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/supabase/web/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supabase/web/jest.config.js b/packages/auth-providers/supabase/web/jest.config.js new file mode 100644 index 000000000000..e691bb8f6dbd --- /dev/null +++ b/packages/auth-providers/supabase/web/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testEnvironment: 'jest-environment-jsdom', + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supabase/web/package.json b/packages/auth-providers/supabase/web/package.json new file mode 100644 index 000000000000..377a558f7e5e --- /dev/null +++ b/packages/auth-providers/supabase/web/package.json @@ -0,0 +1,42 @@ +{ + "name": "@redwoodjs/auth-supabase-web", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supabase/web" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@supabase/supabase-js": "1.35.7", + "@testing-library/react-hooks": "8.0.1", + "@types/react": "17.0.50", + "jest": "29.3.1", + "react": "17.0.2", + "typescript": "4.7.4" + }, + "peerDependencies": { + "@supabase/supabase-js": "1.35.7" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-web/src/supabase/__tests__/supabase.test.tsx b/packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx similarity index 100% rename from packages/auth-providers-web/src/supabase/__tests__/supabase.test.tsx rename to packages/auth-providers/supabase/web/src/__tests__/supabase.test.tsx diff --git a/packages/auth-providers/supabase/web/src/index.ts b/packages/auth-providers/supabase/web/src/index.ts new file mode 100644 index 000000000000..0288173445c0 --- /dev/null +++ b/packages/auth-providers/supabase/web/src/index.ts @@ -0,0 +1 @@ +export { createSupabaseAuth } from './supabase' diff --git a/packages/auth-providers-web/src/supabase/supabase.ts b/packages/auth-providers/supabase/web/src/supabase.ts similarity index 100% rename from packages/auth-providers-web/src/supabase/supabase.ts rename to packages/auth-providers/supabase/web/src/supabase.ts diff --git a/packages/auth-providers/supabase/web/tsconfig.json b/packages/auth-providers/supabase/web/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/supabase/web/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth-providers/supertokens/api/.babelrc.js b/packages/auth-providers/supertokens/api/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supertokens/api/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supertokens/api/README.md b/packages/auth-providers/supertokens/api/README.md new file mode 100644 index 000000000000..d27ea3626dac --- /dev/null +++ b/packages/auth-providers/supertokens/api/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider there's more info in the +[auth docs](https://redwoodjs.com/docs/authentication). + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supertokens/api/jest.config.js b/packages/auth-providers/supertokens/api/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/supertokens/api/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supertokens/api/package.json b/packages/auth-providers/supertokens/api/package.json new file mode 100644 index 000000000000..0cffb644cf00 --- /dev/null +++ b/packages/auth-providers/supertokens/api/package.json @@ -0,0 +1,42 @@ +{ + "name": "@redwoodjs/auth-supertokens-api", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supertokens/api" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "core-js": "3.26.1", + "jsonwebtoken": "8.5.1", + "jwks-rsa": "2.0.5" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@redwoodjs/api": "3.2.0", + "@types/jsonwebtoken": "8.5.9", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "peerDependencies": { + "supertokens-node": "12.1.1" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-api/src/supertokens/__tests__/supertokens.test.ts b/packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts similarity index 100% rename from packages/auth-providers-api/src/supertokens/__tests__/supertokens.test.ts rename to packages/auth-providers/supertokens/api/src/__tests__/supertokens.test.ts diff --git a/packages/auth-providers-api/src/supertokens/decoder.ts b/packages/auth-providers/supertokens/api/src/decoder.ts similarity index 100% rename from packages/auth-providers-api/src/supertokens/decoder.ts rename to packages/auth-providers/supertokens/api/src/decoder.ts diff --git a/packages/auth-providers/supertokens/api/src/index.ts b/packages/auth-providers/supertokens/api/src/index.ts new file mode 100644 index 000000000000..ead5bdde8676 --- /dev/null +++ b/packages/auth-providers/supertokens/api/src/index.ts @@ -0,0 +1 @@ +export { authDecoder } from './decoder' diff --git a/packages/auth-providers/supertokens/api/tsconfig.json b/packages/auth-providers/supertokens/api/tsconfig.json new file mode 100644 index 000000000000..bb9ec4a21fd1 --- /dev/null +++ b/packages/auth-providers/supertokens/api/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../api" }] +} diff --git a/packages/auth-providers/supertokens/setup/.babelrc.js b/packages/auth-providers/supertokens/setup/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supertokens/setup/README.md b/packages/auth-providers/supertokens/setup/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/supertokens/setup/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supertokens/setup/jest.config.js b/packages/auth-providers/supertokens/setup/jest.config.js new file mode 100644 index 000000000000..dee127c25474 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/jest.config.js @@ -0,0 +1,4 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supertokens/setup/package.json b/packages/auth-providers/supertokens/setup/package.json new file mode 100644 index 000000000000..f3995ee77c35 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/package.json @@ -0,0 +1,37 @@ +{ + "name": "@redwoodjs/auth-supertokens-setup", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supertokens/setup" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src --passWithNoTests", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/cli-helpers": "3.2.0", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@types/yargs": "17.0.13", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers/supertokens/setup/src/index.ts b/packages/auth-providers/supertokens/setup/src/index.ts new file mode 100644 index 000000000000..5a774a6b36e2 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/src/index.ts @@ -0,0 +1 @@ +export * from './setup' diff --git a/packages/auth-providers/supertokens/setup/src/setup.ts b/packages/auth-providers/supertokens/setup/src/setup.ts new file mode 100644 index 000000000000..22a52bc18eef --- /dev/null +++ b/packages/auth-providers/supertokens/setup/src/setup.ts @@ -0,0 +1,19 @@ +import yargs from 'yargs' + +import { standardAuthBuilder } from '@redwoodjs/cli-helpers' + +export const command = 'supertokens' +export const description = 'Generate an auth configuration for SuperTokens' + +export async function builder(yargs: yargs.Argv) { + return standardAuthBuilder(yargs) +} + +export interface Args { + force: boolean +} + +export async function handler(options: Args) { + const { handler } = await import('./setupHandler') + return handler(options) +} diff --git a/packages/auth-providers/supertokens/setup/src/setupHandler.ts b/packages/auth-providers/supertokens/setup/src/setupHandler.ts new file mode 100644 index 000000000000..29b27a147dc8 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/src/setupHandler.ts @@ -0,0 +1,33 @@ +import fs from 'fs' +import path from 'path' + +import { standardAuthHandler } from '@redwoodjs/cli-helpers' + +import { Args } from './setup' + +const { version } = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8') +) + +export async function handler({ force: forceArg }: Args) { + standardAuthHandler({ + basedir: __dirname, + forceArg, + provider: 'supertokens', + authDecoderImport: + "import { authDecoder } from '@redwoodjs/auth-supertokens-api'", + apiPackages: [ + `@redwoodjs/auth-supertokens-api@${version}`, + 'supertokens-node', + ], + webPackages: [ + `@redwoodjs/auth-supertokens-web@${version}`, + 'supertokens-auth-react', + ], + notes: [ + "We've generated some example recipe implementations, but do feel free", + 'to switch to something else that better fit your needs.', + 'See: https://supertokens.com/docs/guides', + ], + }) +} diff --git a/packages/auth-providers-setup/src/supertokens/templates/api/functions/auth.ts.template b/packages/auth-providers/supertokens/setup/src/templates/api/functions/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/supertokens/templates/api/functions/auth.ts.template rename to packages/auth-providers/supertokens/setup/src/templates/api/functions/auth.ts.template diff --git a/packages/auth-providers-setup/src/supertokens/templates/api/lib/auth.ts.template b/packages/auth-providers/supertokens/setup/src/templates/api/lib/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/supertokens/templates/api/lib/auth.ts.template rename to packages/auth-providers/supertokens/setup/src/templates/api/lib/auth.ts.template diff --git a/packages/auth-providers-setup/src/supertokens/templates/api/lib/supertokens.ts.template b/packages/auth-providers/supertokens/setup/src/templates/api/lib/supertokens.ts.template similarity index 100% rename from packages/auth-providers-setup/src/supertokens/templates/api/lib/supertokens.ts.template rename to packages/auth-providers/supertokens/setup/src/templates/api/lib/supertokens.ts.template diff --git a/packages/auth-providers-setup/src/supertokens/templates/web/auth.ts.template b/packages/auth-providers/supertokens/setup/src/templates/web/auth.ts.template similarity index 93% rename from packages/auth-providers-setup/src/supertokens/templates/web/auth.ts.template rename to packages/auth-providers/supertokens/setup/src/templates/web/auth.ts.template index ea3cd1c03635..c14a47b01665 100644 --- a/packages/auth-providers-setup/src/supertokens/templates/web/auth.ts.template +++ b/packages/auth-providers/supertokens/setup/src/templates/web/auth.ts.template @@ -1,4 +1,4 @@ -import { createSuperTokensAuth } from '@redwoodjs/auth-providers-web' +import { createSuperTokensAuth } from '@redwoodjs/auth-supertokens-web' import { isBrowser } from '@redwoodjs/prerender/browserUtils' import SuperTokens from 'supertokens-auth-react' diff --git a/packages/auth-providers/supertokens/setup/tsconfig.json b/packages/auth-providers/supertokens/setup/tsconfig.json new file mode 100644 index 000000000000..abb54b70112a --- /dev/null +++ b/packages/auth-providers/supertokens/setup/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../cli-helpers" }] +} diff --git a/packages/auth-providers/supertokens/web/.babelrc.js b/packages/auth-providers/supertokens/web/.babelrc.js new file mode 100644 index 000000000000..4312886a07e5 --- /dev/null +++ b/packages/auth-providers/supertokens/web/.babelrc.js @@ -0,0 +1 @@ +module.exports = { extends: '../../../../babel.config.js' } diff --git a/packages/auth-providers/supertokens/web/README.md b/packages/auth-providers/supertokens/web/README.md new file mode 100644 index 000000000000..661208df586e --- /dev/null +++ b/packages/auth-providers/supertokens/web/README.md @@ -0,0 +1,141 @@ +# Authentication + +## Contributing + +If you want to contribute a new auth provider integration we recommend you +start by implementing it as a custom auth provider in a Redwood App first. When +that works you can package it up as an npm package and publish it on your own. +You can then create a PR on this repo with support for your new auth provider +in our `yarn rw setup auth` cli command. The easiest option is probably to just +look at one of the existing auth providers in +`packages/cli/src/commands/setup/auth/providers` and the corresponding +templates in `../templates`. + +If you need help setting up a custom auth provider you can read the auth docs +on the web. + +### Contributing to the base auth implementation + +If you want to contribute to our auth implementation, the interface towards +both auth service providers and RW apps we recommend you start looking in +`authFactory.ts` and then continue to `AuthProvider.tsx`. `AuthProvider.tsx` +has most of our implementation together with all the custom hooks it uses. +Another file to be accustomed with is `AuthContext.ts`. The interface in there +has pretty god code comments, and is what will be exposed to RW apps. + +## getCurrentUser + +`getCurrentUser` returns the user information together with +an optional collection of roles used by requireAuth() to check if the user is authenticated or has role-based access. + +Use in conjunction with `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param decoded - The decoded access token containing user info and JWT claims like `sub` +@param { token, SupportedAuthTypes type } - The access token itself as well as the auth provider type +@param { APIGatewayEvent event, Context context } - An object which contains information from the invoker +such as headers and cookies, and the context information about the invocation such as IP Address +``` + +### Examples + +#### Checks if currentUser is authenticated + +This example is the standard use of `getCurrentUser`. + +```js +export const getCurrentUser = async (decoded, { _token, _type }, { _event, _context }) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User details fetched via database query + +```js +export const getCurrentUser = async (decoded) => { + return await db.user.findUnique({ where: { decoded.email } }) +} +``` + +#### User info is decoded from the access token + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded } +} +``` + +#### User info is contained in the decoded token and roles extracted + +```js +export const getCurrentUser = async (decoded) => { + return { ...decoded, roles: parseJWT({ decoded }).roles } +} +``` + +#### User record query by email with namespaced app_metadata roles as Auth0 requires custom JWT claims to be namespaced + +```js +export const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { email: decoded.email } }) + + return { + ...currentUser, + roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles, + } +} +``` + +#### User record query by an identity with app_metadata roles + +```js +const getCurrentUser = async (decoded) => { + const currentUser = await db.user.findUnique({ where: { userIdentity: decoded.sub } }) + return { + ...currentUser, + roles: parseJWT({ decoded: decoded }).roles, + } +} +``` + +#### Cookies and other request information are available in the req parameter, just in case + +```js +const getCurrentUser = async (_decoded, _raw, { event, _context }) => { + const cookies = cookie(event.headers.cookies) + const session = cookies['my.cookie.name'] + const currentUser = await db.sessions.findUnique({ where: { id: session } }) + return currentUser +} +``` + + +## requireAuth + + Use `requireAuth` in your services to check that a user is logged in, whether or not they are assigned a role, and optionally raise an error if they're not. + +```js +@param {string=} roles - An optional role or list of roles +@param {string[]=} roles - An optional list of roles + +@returns {boolean} - If the currentUser is authenticated (and assigned one of the given roles) + +@throws {AuthenticationError} - If the currentUser is not authenticated +@throws {ForbiddenError} If the currentUser is not allowed due to role permissions +``` + +### Examples + +#### Checks if currentUser is authenticated + +```js +requireAuth() +``` + +#### Checks if currentUser is authenticated and assigned one of the given roles + +```js + requireAuth({ role: 'admin' }) + requireAuth({ role: ['editor', 'author'] }) + requireAuth({ role: ['publisher'] }) +``` diff --git a/packages/auth-providers/supertokens/web/jest.config.js b/packages/auth-providers/supertokens/web/jest.config.js new file mode 100644 index 000000000000..e691bb8f6dbd --- /dev/null +++ b/packages/auth-providers/supertokens/web/jest.config.js @@ -0,0 +1,5 @@ +/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + testEnvironment: 'jest-environment-jsdom', + testPathIgnorePatterns: ['fixtures', 'dist'], +} diff --git a/packages/auth-providers/supertokens/web/package.json b/packages/auth-providers/supertokens/web/package.json new file mode 100644 index 000000000000..640aef82e9de --- /dev/null +++ b/packages/auth-providers/supertokens/web/package.json @@ -0,0 +1,42 @@ +{ + "name": "@redwoodjs/auth-supertokens-web", + "version": "3.2.0", + "repository": { + "type": "git", + "url": "https://github.com/redwoodjs/redwood.git", + "directory": "packages/auth-providers/supertokens/web" + }, + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "yarn build:js && yarn build:types", + "build:js": "babel src -d dist --extensions \".js,.ts,.tsx\" --copy-files --no-copy-ignored", + "build:types": "tsc --build --verbose", + "build:watch": "nodemon --watch src --ext \"js,ts,tsx,template\" --ignore dist --exec \"yarn build\"", + "prepublishOnly": "NODE_ENV=production yarn build", + "test": "jest src", + "test:watch": "yarn test --watch" + }, + "dependencies": { + "@babel/runtime-corejs3": "7.20.6", + "@redwoodjs/auth": "3.2.0", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@testing-library/react-hooks": "8.0.1", + "@types/react": "17.0.50", + "jest": "29.3.1", + "react": "17.0.2", + "typescript": "4.7.4" + }, + "peerDependencies": { + "supertokens-auth-react": "0.26.5" + }, + "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" +} diff --git a/packages/auth-providers-web/src/supertokens/__tests__/supertokens.test.tsx b/packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx similarity index 100% rename from packages/auth-providers-web/src/supertokens/__tests__/supertokens.test.tsx rename to packages/auth-providers/supertokens/web/src/__tests__/supertokens.test.tsx diff --git a/packages/auth-providers/supertokens/web/src/index.ts b/packages/auth-providers/supertokens/web/src/index.ts new file mode 100644 index 000000000000..93e2d5d5ef69 --- /dev/null +++ b/packages/auth-providers/supertokens/web/src/index.ts @@ -0,0 +1 @@ +export { createSuperTokensAuth } from './supertokens' diff --git a/packages/auth-providers-web/src/supertokens/supertokens.ts b/packages/auth-providers/supertokens/web/src/supertokens.ts similarity index 100% rename from packages/auth-providers-web/src/supertokens/supertokens.ts rename to packages/auth-providers/supertokens/web/src/supertokens.ts diff --git a/packages/auth-providers/supertokens/web/tsconfig.json b/packages/auth-providers/supertokens/web/tsconfig.json new file mode 100644 index 000000000000..a925964c5e44 --- /dev/null +++ b/packages/auth-providers/supertokens/web/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../../tsconfig.compilerOption.json", + "compilerOptions": { + "strict": true, + "baseUrl": ".", + "rootDir": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo", + "outDir": "dist" + }, + "include": ["src"], + "references": [{ "path": "../../../auth" }] +} diff --git a/packages/auth/package.json b/packages/auth/package.json index d0489ec0dfb1..10df38f72c48 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -23,33 +23,17 @@ }, "dependencies": { "@babel/runtime-corejs3": "7.20.6", - "core-js": "3.26.1" + "core-js": "3.26.1", + "react": "17.0.2" }, "devDependencies": { - "@auth0/auth0-spa-js": "1.22.5", - "@azure/msal-browser": "2.30.0", "@babel/cli": "7.19.3", "@babel/core": "7.20.5", - "@clerk/clerk-js": "3.17.0", - "@clerk/clerk-react": "3.5.1", - "@clerk/clerk-sdk-node": "3.9.2", - "@clerk/types": "2.21.0", - "@nhost/hasura-auth-js": "1.4.1", - "@nhost/nhost-js": "1.4.10", - "@okta/okta-auth-js": "6.9.0", - "@simplewebauthn/browser": "6.2.1", - "@simplewebauthn/typescript-types": "6.2.1", - "@supabase/supabase-js": "1.35.7", - "@types/netlify-identity-widget": "1.9.3", - "@types/react": "17.0.50", - "firebase": "9.10.0", - "firebase-admin": "10.3.0", - "gotrue-js": "0.9.29", + "@testing-library/jest-dom": "5.16.5", + "@testing-library/react": "12.1.5", + "@testing-library/react-hooks": "8.0.1", "jest": "29.3.1", - "magic-sdk": "9.1.1", - "netlify-identity-widget": "1.9.2", - "react": "17.0.2", - "supertokens-auth-react": "0.26.5", + "msw": "0.49.1", "typescript": "4.7.4" }, "gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1" diff --git a/packages/cli-helpers/src/auth/authTasks.ts b/packages/cli-helpers/src/auth/authTasks.ts index 5df7ba5e06aa..4c3835538c24 100644 --- a/packages/cli-helpers/src/auth/authTasks.ts +++ b/packages/cli-helpers/src/auth/authTasks.ts @@ -353,27 +353,19 @@ export const addAuthConfigToGqlApi = ( }, }) -export const addWebPackages = (webPackages: string[], rwVersion: string) => ({ +export const addWebPackages = (webPackages: string[]) => ({ title: 'Adding required web packages...', task: async () => { - const args = [ - 'workspace', - 'web', - 'add', - ...webPackages, - `@redwoodjs/auth@${rwVersion}`, - ] - await execa('yarn', args) + await execa('yarn', ['workspace', 'web', 'add', ...webPackages]) }, }) -export const addApiPackages = (apiPackages: string[]) => - apiPackages.length > 0 && { - title: 'Adding required api packages...', - task: async () => { - await execa('yarn', ['workspace', 'api', 'add', ...apiPackages]) - }, - } +export const addApiPackages = (apiPackages: string[]) => ({ + title: 'Adding required api packages...', + task: async () => { + await execa('yarn', ['workspace', 'api', 'add', ...apiPackages]) + }, +}) export const installPackages = { title: 'Installing packages...', diff --git a/packages/cli-helpers/src/auth/setupHelpers.ts b/packages/cli-helpers/src/auth/setupHelpers.ts index 2b2ac0b7d04e..ccfa477995e8 100644 --- a/packages/cli-helpers/src/auth/setupHelpers.ts +++ b/packages/cli-helpers/src/auth/setupHelpers.ts @@ -68,7 +68,6 @@ export const standardAuthBuilder = (yargs: yargs.Argv) => { interface Args { basedir: string - rwVersion: string forceArg: boolean provider: string authDecoderImport?: string @@ -88,7 +87,6 @@ function truthy(value: T): value is Truthy { export const standardAuthHandler = async ({ basedir, - rwVersion, forceArg, provider, authDecoderImport, @@ -105,16 +103,16 @@ export const standardAuthHandler = async ({ generateAuthApiFiles(basedir, provider, force, webAuthn), addAuthConfigToWeb(basedir, provider, webAuthn), addAuthConfigToGqlApi(authDecoderImport), - addWebPackages(webPackages, rwVersion), - addApiPackages(apiPackages), - installPackages, + webPackages.length && addWebPackages(webPackages), + apiPackages.length && addApiPackages(apiPackages), + (webPackages.length || apiPackages.length) && installPackages, extraTask, notes && { title: 'One more thing...', task: () => { // Can't console.log the notes here because of - // https://github.com/cenk1cenk2/listr2/issues/296 - // So we do it after the tasks have all finished instead + // https://github.com/cenk1cenk2/listr2/issues/296. + // So we do it after the tasks have all finished instead. }, }, ].filter(truthy), diff --git a/packages/cli/src/commands/setup/auth/auth.js b/packages/cli/src/commands/setup/auth/auth.js index a27521e73d83..df3b42c64122 100644 --- a/packages/cli/src/commands/setup/auth/auth.js +++ b/packages/cli/src/commands/setup/auth/auth.js @@ -9,16 +9,13 @@ export const description = 'Generate an auth configuration' export async function builder(yargs) { const { - setupAuthClerkCommand, - setupAuthDbAuthCommand, setupAuthEthereumCommand, setupAuthGoTrueCommand, setupAuthMagicLinkCommand, setupAuthNhostCommand, setupAuthOktaCommand, - setupAuthSupabaseCommand, - setupAuthSupertokensCommand, } = await import('@redwoodjs/auth-providers-setup') + // Don't forget to update test-project setup if you change something here const printExperimentalWarning = async (argv, yargs) => { if (!argv.warn) { @@ -61,18 +58,23 @@ export async function builder(yargs) { 'https://redwoodjs.com/docs/cli-commands#setup-auth' )}` ) - - .command(setupAuthClerkCommand) - .command(setupAuthDbAuthCommand) .command(setupAuthEthereumCommand) .command(setupAuthGoTrueCommand) .command(setupAuthMagicLinkCommand) .command(setupAuthNhostCommand) .command(setupAuthOktaCommand) - .command(setupAuthSupabaseCommand) - .command(setupAuthSupertokensCommand) - async function addSetupCommand(module, namedExport) { + for (const module of [ + '@redwoodjs/auth0-setup', + '@redwoodjs/auth-custom-setup', + '@redwoodjs/auth-netlify-setup', + '@redwoodjs/auth-firebase-setup', + '@redwoodjs/azure-active-directory-setup', + '@redwoodjs/clerk-setup', + '@redwoodjs/dbauth-setup', + '@redwoodjs/auth-supabase-setup', + '@redwoodjs/supertokens-setup', + ]) { let commandModule try { @@ -82,24 +84,12 @@ export async function builder(yargs) { if (e.code === 'MODULE_NOT_FOUND') { return } + throw e } if (commandModule) { - setupAuthCommand.command(commandModule[namedExport]) + setupAuthCommand.command(commandModule) } } - - for (const [module, namedExport] of [ - ['@redwoodjs/auth-auth0-setup', 'setupAuthAuth0Command'], - [ - '@redwoodjs/auth-azure-active-directory-setup', - 'setupAuthAzureActiveDirectoryCommand ', - ], - ['@redwoodjs/auth-custom-setup', 'setupAuthCustomCommand'], - ['@redwoodjs/auth-netlify-setup', 'setupAuthNetlifyCommand'], - ['@redwoodjs/auth-firebase-setup', 'setupAuthFirebaseCommand'], - ]) { - await addSetupCommand(module, namedExport) - } } diff --git a/yarn.lock b/yarn.lock index 73a7306c0f73..09bd2ccdc4bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1008,7 +1008,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.12.13, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2": +"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.18.6 resolution: "@babel/plugin-syntax-jsx@npm:7.18.6" dependencies: @@ -1753,7 +1753,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.0, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.0, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": version: 7.18.9 resolution: "@babel/runtime@npm:7.18.9" dependencies: @@ -1828,28 +1828,6 @@ __metadata: languageName: node linkType: hard -"@clerk/clerk-js@npm:3.17.0": - version: 3.17.0 - resolution: "@clerk/clerk-js@npm:3.17.0" - dependencies: - "@clerk/types": ^2.21.0 - "@emotion/cache": ^11.7.1 - "@emotion/react": ^11.9.0 - "@popperjs/core": ^2.4.4 - browser-tabs-lock: ^1.2.15 - classnames: ^2.3.1 - core-js: ^3.18.3 - deepmerge: ^4.2.2 - js-cookie: ^2.2.1 - qs: ^6.9.4 - react: 17.0.2 - react-dom: 17.0.2 - react-popper: ^2.2.3 - regenerator-runtime: ^0.13.7 - checksum: 0dc49d863d31154cde1818a992aaff72437081a442b911c0b116fdb147eee23cdb802a7808447afe7c4efb5aa1ebf2254a3df83bbe44977c05711eb8f8eeba97 - languageName: node - linkType: hard - "@clerk/clerk-react@npm:3.5.1": version: 3.5.1 resolution: "@clerk/clerk-react@npm:3.5.1" @@ -1953,119 +1931,6 @@ __metadata: languageName: node linkType: hard -"@emotion/babel-plugin@npm:^11.7.1": - version: 11.9.2 - resolution: "@emotion/babel-plugin@npm:11.9.2" - dependencies: - "@babel/helper-module-imports": ^7.12.13 - "@babel/plugin-syntax-jsx": ^7.12.13 - "@babel/runtime": ^7.13.10 - "@emotion/hash": ^0.8.0 - "@emotion/memoize": ^0.7.5 - "@emotion/serialize": ^1.0.2 - babel-plugin-macros: ^2.6.1 - convert-source-map: ^1.5.0 - escape-string-regexp: ^4.0.0 - find-root: ^1.1.0 - source-map: ^0.5.7 - stylis: 4.0.13 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 337d683a657f14fd9f30a50561794e9b7b986c4dfa3de4747defb38f7f352eedae56bf73b1ff6e315f05e938b7e6c11e100c3a1485722d9bcdc4018f32b9b9a1 - languageName: node - linkType: hard - -"@emotion/cache@npm:^11.4.0, @emotion/cache@npm:^11.7.1, @emotion/cache@npm:^11.9.3": - version: 11.9.3 - resolution: "@emotion/cache@npm:11.9.3" - dependencies: - "@emotion/memoize": ^0.7.4 - "@emotion/sheet": ^1.1.1 - "@emotion/utils": ^1.0.0 - "@emotion/weak-memoize": ^0.2.5 - stylis: 4.0.13 - checksum: 8592bc55bfe331ce8bd1bc4900a0fec801dc916d191400b8a4b10551ca37b05d3a21aa53cddd23929469f9e5361ef0591b03b6963da66cfe5d282df82e26e0a6 - languageName: node - linkType: hard - -"@emotion/hash@npm:^0.8.0": - version: 0.8.0 - resolution: "@emotion/hash@npm:0.8.0" - checksum: 706303d35d416217cd7eb0d36dbda4627bb8bdf4a32ea387e8dd99be11b8e0a998e10af21216e8a5fade518ad955ff06aa8890f20e694ce3a038ae7fc1000556 - languageName: node - linkType: hard - -"@emotion/memoize@npm:^0.7.4, @emotion/memoize@npm:^0.7.5": - version: 0.7.5 - resolution: "@emotion/memoize@npm:0.7.5" - checksum: 28d061ec9fb9b8c495d58b4e2dcc62207d75d4e8d8f4e6a0b42342d6e7c649d41461e807363d1a0a2c33d2235f6ee59dd6394fbec88b7da65e3d5852fc34387e - languageName: node - linkType: hard - -"@emotion/react@npm:^11.1.1, @emotion/react@npm:^11.4.1, @emotion/react@npm:^11.9.0": - version: 11.9.3 - resolution: "@emotion/react@npm:11.9.3" - dependencies: - "@babel/runtime": ^7.13.10 - "@emotion/babel-plugin": ^11.7.1 - "@emotion/cache": ^11.9.3 - "@emotion/serialize": ^1.0.4 - "@emotion/utils": ^1.1.0 - "@emotion/weak-memoize": ^0.2.5 - hoist-non-react-statics: ^3.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - react: ">=16.8.0" - peerDependenciesMeta: - "@babel/core": - optional: true - "@types/react": - optional: true - checksum: f32dbae3110d4c391d6ec51d8c3d86235303d858c8ebf1e90b3d35bcadeb73c0f4557e73ba824e9dbf7f269d0413bc2877e3f4bc2e2b1157b08fbb10b51e18eb - languageName: node - linkType: hard - -"@emotion/serialize@npm:^1.0.2, @emotion/serialize@npm:^1.0.4": - version: 1.0.4 - resolution: "@emotion/serialize@npm:1.0.4" - dependencies: - "@emotion/hash": ^0.8.0 - "@emotion/memoize": ^0.7.4 - "@emotion/unitless": ^0.7.5 - "@emotion/utils": ^1.0.0 - csstype: ^3.0.2 - checksum: ad2d5aba32177ae305918ccebd1e7a8d1d2886dc2083d9a031853169f9713012aee998ddd8a3d62d63eade1cfa4c077de5b260ed664a77583428d3df65dd193a - languageName: node - linkType: hard - -"@emotion/sheet@npm:^1.1.1": - version: 1.1.1 - resolution: "@emotion/sheet@npm:1.1.1" - checksum: be65c618965123b9012eb9535e256a6ba172bd67389f91de8a38dd4db00bed2534e8f5a2b22e2ab2fabb41946259bedc1c18c09acd24021490484aeed9bb1f90 - languageName: node - linkType: hard - -"@emotion/unitless@npm:^0.7.5": - version: 0.7.5 - resolution: "@emotion/unitless@npm:0.7.5" - checksum: 4d0d94f53cb97b4481bbfa394953e1899a0b877644642ba9dd7247c27eb8c48e14e22aeb11411d7d9874685ad85dd5fb5b50eb78c6d8840eb56a84b92dcef2f4 - languageName: node - linkType: hard - -"@emotion/utils@npm:^1.0.0, @emotion/utils@npm:^1.1.0": - version: 1.1.0 - resolution: "@emotion/utils@npm:1.1.0" - checksum: 4659bb4c447fa8c5303fae5cae829c22ce29ba0d9e0a8fb1f3f33b8bfd9304a435af327abccbf133040eeb1771a572fad3e68decd267e26459b8ea6ea1f2ba68 - languageName: node - linkType: hard - -"@emotion/weak-memoize@npm:^0.2.5": - version: 0.2.5 - resolution: "@emotion/weak-memoize@npm:0.2.5" - checksum: cabfaaecabbb407d323098afc0bb2dd2ec9aaea0672f8f2c54b84b99d5f8cc680356cf166583fd5593330ceef29f2c26554c2c65dff06c0a8f5f8c7da69d89f1 - languageName: node - linkType: hard - "@envelop/core@npm:^2.5.0": version: 2.5.0 resolution: "@envelop/core@npm:2.5.0" @@ -6046,13 +5911,6 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.4.4": - version: 2.11.2 - resolution: "@popperjs/core@npm:2.11.2" - checksum: b06f65fcef9dbfe7487fd53e38f12684267e91c8bc667a6c9621c207f42ee97d48059039ee8dae0327df509234b6f09bf5b940b34b71ee453d307f53d84e99b2 - languageName: node - linkType: hard - "@prisma/client@npm:4.7.0": version: 4.7.0 resolution: "@prisma/client@npm:4.7.0" @@ -6479,14 +6337,13 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 "@types/jsonwebtoken": 8.5.9 core-js: 3.26.1 jest: 29.3.1 jsonwebtoken: 8.5.1 jwks-rsa: 2.0.5 typescript: 4.7.4 - peerDependencies: - "@redwoodjs/api": 3.2.0 languageName: unknown linkType: soft @@ -6509,9 +6366,11 @@ __metadata: version: 0.0.0-use.local resolution: "@redwoodjs/auth-auth0-web@workspace:packages/auth-providers/auth0/web" dependencies: + "@auth0/auth0-spa-js": 1.22.5 "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 "@testing-library/react-hooks": 8.0.1 "@types/react": 17.0.50 core-js: 3.26.1 @@ -6520,7 +6379,6 @@ __metadata: typescript: 4.7.4 peerDependencies: "@auth0/auth0-spa-js": 1.22.5 - "@redwoodjs/auth": 3.2.0 languageName: unknown linkType: soft @@ -6531,13 +6389,14 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 + "@types/aws-lambda": 8.10.107 "@types/jsonwebtoken": 8.5.9 core-js: 3.26.1 jest: 29.3.1 jsonwebtoken: 8.5.1 + jwks-rsa: 2.0.5 typescript: 4.7.4 - peerDependencies: - "@redwoodjs/api": 3.2.0 languageName: unknown linkType: soft @@ -6564,6 +6423,7 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 "@testing-library/react-hooks": 8.0.1 "@types/netlify-identity-widget": 1.9.3 "@types/react": 17.0.50 @@ -6573,7 +6433,58 @@ __metadata: typescript: 4.7.4 peerDependencies: "@azure/msal-browser": 2.30.0 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-clerk-api@workspace:packages/auth-providers/clerk/api": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-clerk-api@workspace:packages/auth-providers/clerk/api" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@clerk/clerk-sdk-node": 3.9.2 + "@redwoodjs/api": 3.2.0 + "@types/aws-lambda": 8.10.107 + core-js: 3.26.1 + jest: 29.3.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-clerk-setup@workspace:packages/auth-providers/clerk/setup": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-clerk-setup@workspace:packages/auth-providers/clerk/setup" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/cli-helpers": 3.2.0 + "@types/yargs": 17.0.13 + core-js: 3.26.1 + jest: 29.3.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-clerk-web@workspace:packages/auth-providers/clerk/web": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-clerk-web@workspace:packages/auth-providers/clerk/web" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@clerk/clerk-react": 3.5.1 + "@clerk/types": 2.21.0 "@redwoodjs/auth": 3.2.0 + "@testing-library/react-hooks": 8.0.1 + "@types/react": 17.0.50 + core-js: 3.26.1 + jest: 29.3.1 + react: 17.0.2 + typescript: 4.7.4 + peerDependencies: + "@clerk/clerk-react": 3.5.1 languageName: unknown linkType: soft @@ -6592,6 +6503,67 @@ __metadata: languageName: unknown linkType: soft +"@redwoodjs/auth-dbauth-api@workspace:packages/auth-providers/dbAuth/api": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-dbauth-api@workspace:packages/auth-providers/dbAuth/api" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 + "@types/crypto-js": 4.1.1 + "@types/md5": 2.3.2 + "@types/uuid": 8.3.4 + base64url: 3.0.1 + core-js: 3.26.1 + crypto-js: 4.1.1 + jest: 29.3.1 + md5: 2.3.0 + typescript: 4.7.4 + uuid: 9.0.0 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-dbauth-setup@workspace:packages/auth-providers/dbAuth/setup": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-dbauth-setup@workspace:packages/auth-providers/dbAuth/setup" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/cli-helpers": 3.2.0 + "@simplewebauthn/browser": 6.2.1 + "@simplewebauthn/typescript-types": 6.2.1 + "@types/secure-random-password": 0.2.1 + "@types/yargs": 17.0.13 + core-js: 3.26.1 + jest: 29.3.1 + prompts: 2.4.2 + secure-random-password: 0.2.3 + terminal-link: 2.1.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-dbauth-web@workspace:packages/auth-providers/dbAuth/web": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-dbauth-web@workspace:packages/auth-providers/dbAuth/web" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 + "@simplewebauthn/browser": 6.2.1 + "@simplewebauthn/typescript-types": 6.2.1 + "@testing-library/react-hooks": 8.0.1 + "@types/react": 17.0.50 + core-js: 3.26.1 + jest: 29.3.1 + react: 17.0.2 + typescript: 4.7.4 + languageName: unknown + linkType: soft + "@redwoodjs/auth-firebase-api@workspace:packages/auth-providers/firebase/api": version: 0.0.0-use.local resolution: "@redwoodjs/auth-firebase-api@workspace:packages/auth-providers/firebase/api" @@ -6599,13 +6571,12 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 "@types/aws-lambda": 8.10.107 core-js: 3.26.1 firebase-admin: 10.3.0 jest: 29.3.1 typescript: 4.7.4 - peerDependencies: - "@redwoodjs/api": 3.2.0 languageName: unknown linkType: soft @@ -6631,6 +6602,7 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 "@testing-library/react-hooks": 8.0.1 "@types/react": 17.0.50 core-js: 3.26.1 @@ -6639,7 +6611,6 @@ __metadata: react: 17.0.2 typescript: 4.7.4 peerDependencies: - "@redwoodjs/auth": 3.2.0 firebase: 9.10.0 languageName: unknown linkType: soft @@ -6651,14 +6622,13 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 "@types/aws-lambda": 8.10.107 "@types/jsonwebtoken": 8.5.9 core-js: 3.26.1 jest: 29.3.1 jsonwebtoken: 8.5.1 typescript: 4.7.4 - peerDependencies: - "@redwoodjs/api": 3.2.0 languageName: unknown linkType: soft @@ -6684,6 +6654,7 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 "@testing-library/react-hooks": 8.0.1 "@types/netlify-identity-widget": 1.9.3 "@types/react": 17.0.50 @@ -6692,7 +6663,6 @@ __metadata: react: 17.0.2 typescript: 4.7.4 peerDependencies: - "@redwoodjs/auth": 3.2.0 netlify-identity-widget: 1.9.2 languageName: unknown linkType: soft @@ -6701,58 +6671,31 @@ __metadata: version: 0.0.0-use.local resolution: "@redwoodjs/auth-providers-api@workspace:packages/auth-providers-api" dependencies: - "@auth0/auth0-spa-js": 1.22.5 - "@azure/msal-browser": 2.30.0 "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 - "@clerk/clerk-js": 3.17.0 - "@clerk/clerk-react": 3.5.1 - "@clerk/clerk-sdk-node": 3.9.2 - "@clerk/types": 2.21.0 "@magic-sdk/admin": 1.4.1 "@nhost/hasura-auth-js": 1.4.1 "@nhost/nhost-js": 1.4.10 "@okta/jwt-verifier": 2.6.0 "@okta/okta-auth-js": 6.9.0 - "@redwoodjs/auth": 3.2.0 - "@redwoodjs/cli-helpers": 3.2.0 - "@simplewebauthn/browser": 6.2.1 - "@simplewebauthn/typescript-types": 6.2.1 - "@supabase/supabase-js": 1.35.7 + "@redwoodjs/api": 3.2.0 + "@types/aws-lambda": 8.10.107 "@types/jsonwebtoken": 8.5.9 - "@types/netlify-identity-widget": 1.9.3 - "@types/react": 17.0.50 - "@types/uuid": 8.3.4 core-js: 3.26.1 - firebase: 9.10.0 - firebase-admin: 10.3.0 gotrue-js: 0.9.29 jest: 29.3.1 jsonwebtoken: 8.5.1 magic-sdk: 9.1.1 - netlify-identity-widget: 1.9.2 - react: 17.0.2 - supertokens-auth-react: 0.26.5 typescript: 4.7.4 - uuid: 9.0.0 peerDependencies: - "@clerk/clerk-react": 3.5.1 - "@clerk/clerk-sdk-node": 3.9.2 "@magic-sdk/admin": 1.4.1 "@okta/jwt-verifier": 2.6.0 - firebase-admin: 10.3.0 peerDependenciesMeta: - "@clerk/clerk-react": - optional: true - "@clerk/clerk-sdk-node": - optional: true "@magic-sdk/admin": optional: true "@okta/jwt-verifier": optional: true - firebase-admin: - optional: true languageName: unknown linkType: soft @@ -6763,13 +6706,10 @@ __metadata: "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 - "@redwoodjs/auth": 3.2.0 "@redwoodjs/cli-helpers": 3.2.0 - "@types/react": 17.0.50 - "@types/secure-random-password": 0.2.1 + "@types/yargs": 17.0.13 core-js: 3.26.1 jest: 29.3.1 - secure-random-password: 0.2.3 typescript: 4.7.4 languageName: unknown linkType: soft @@ -6778,53 +6718,132 @@ __metadata: version: 0.0.0-use.local resolution: "@redwoodjs/auth-providers-web@workspace:packages/auth-providers-web" dependencies: - "@auth0/auth0-spa-js": 1.22.5 - "@azure/msal-browser": 2.30.0 "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 - "@clerk/clerk-js": 3.17.0 - "@clerk/clerk-react": 3.5.1 - "@clerk/clerk-sdk-node": 3.9.2 - "@clerk/types": 2.21.0 "@nhost/hasura-auth-js": 1.4.1 "@nhost/nhost-js": 1.4.10 "@okta/okta-auth-js": 6.9.0 "@redwoodjs/auth": 3.2.0 - "@simplewebauthn/browser": 6.2.1 - "@simplewebauthn/typescript-types": 6.2.1 - "@supabase/supabase-js": 1.35.7 - "@types/netlify-identity-widget": 1.9.3 "@types/react": 17.0.50 - "@types/uuid": 8.3.4 core-js: 3.26.1 - firebase: 9.10.0 - firebase-admin: 10.3.0 gotrue-js: 0.9.29 jest: 29.3.1 magic-sdk: 9.1.1 - netlify-identity-widget: 1.9.2 react: 17.0.2 - supertokens-auth-react: 0.26.5 typescript: 4.7.4 - uuid: 9.0.0 peerDependencies: - "@clerk/clerk-react": 3.5.1 - "@clerk/clerk-sdk-node": 3.9.2 "@magic-sdk/admin": 1.4.1 "@okta/jwt-verifier": 2.6.0 - firebase-admin: 10.3.0 peerDependenciesMeta: - "@clerk/clerk-react": - optional: true - "@clerk/clerk-sdk-node": - optional: true "@magic-sdk/admin": optional: true "@okta/jwt-verifier": optional: true - firebase-admin: - optional: true + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supabase-api@workspace:packages/auth-providers/supabase/api": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supabase-api@workspace:packages/auth-providers/supabase/api" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 + "@types/aws-lambda": 8.10.107 + "@types/jsonwebtoken": 8.5.9 + core-js: 3.26.1 + jest: 29.3.1 + jsonwebtoken: 8.5.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supabase-setup@workspace:packages/auth-providers/supabase/setup": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supabase-setup@workspace:packages/auth-providers/supabase/setup" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/cli-helpers": 3.2.0 + "@types/yargs": 17.0.13 + core-js: 3.26.1 + jest: 29.3.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supabase-web@workspace:packages/auth-providers/supabase/web": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supabase-web@workspace:packages/auth-providers/supabase/web" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@supabase/supabase-js": 1.35.7 + "@testing-library/react-hooks": 8.0.1 + "@types/react": 17.0.50 + core-js: 3.26.1 + jest: 29.3.1 + react: 17.0.2 + typescript: 4.7.4 + peerDependencies: + "@supabase/supabase-js": 1.35.7 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supertokens-api@workspace:packages/auth-providers/supertokens/api": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supertokens-api@workspace:packages/auth-providers/supertokens/api" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/api": 3.2.0 + "@types/jsonwebtoken": 8.5.9 + core-js: 3.26.1 + jest: 29.3.1 + jsonwebtoken: 8.5.1 + jwks-rsa: 2.0.5 + typescript: 4.7.4 + peerDependencies: + supertokens-node: 12.1.1 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supertokens-setup@workspace:packages/auth-providers/supertokens/setup": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supertokens-setup@workspace:packages/auth-providers/supertokens/setup" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/cli-helpers": 3.2.0 + "@types/yargs": 17.0.13 + core-js: 3.26.1 + jest: 29.3.1 + typescript: 4.7.4 + languageName: unknown + linkType: soft + +"@redwoodjs/auth-supertokens-web@workspace:packages/auth-providers/supertokens/web": + version: 0.0.0-use.local + resolution: "@redwoodjs/auth-supertokens-web@workspace:packages/auth-providers/supertokens/web" + dependencies: + "@babel/cli": 7.19.3 + "@babel/core": 7.20.5 + "@babel/runtime-corejs3": 7.20.6 + "@redwoodjs/auth": 3.2.0 + "@testing-library/react-hooks": 8.0.1 + "@types/react": 17.0.50 + core-js: 3.26.1 + jest: 29.3.1 + react: 17.0.2 + typescript: 4.7.4 + peerDependencies: + supertokens-auth-react: 0.26.5 languageName: unknown linkType: soft @@ -6832,32 +6851,16 @@ __metadata: version: 0.0.0-use.local resolution: "@redwoodjs/auth@workspace:packages/auth" dependencies: - "@auth0/auth0-spa-js": 1.22.5 - "@azure/msal-browser": 2.30.0 "@babel/cli": 7.19.3 "@babel/core": 7.20.5 "@babel/runtime-corejs3": 7.20.6 - "@clerk/clerk-js": 3.17.0 - "@clerk/clerk-react": 3.5.1 - "@clerk/clerk-sdk-node": 3.9.2 - "@clerk/types": 2.21.0 - "@nhost/hasura-auth-js": 1.4.1 - "@nhost/nhost-js": 1.4.10 - "@okta/okta-auth-js": 6.9.0 - "@simplewebauthn/browser": 6.2.1 - "@simplewebauthn/typescript-types": 6.2.1 - "@supabase/supabase-js": 1.35.7 - "@types/netlify-identity-widget": 1.9.3 - "@types/react": 17.0.50 + "@testing-library/jest-dom": 5.16.5 + "@testing-library/react": 12.1.5 + "@testing-library/react-hooks": 8.0.1 core-js: 3.26.1 - firebase: 9.10.0 - firebase-admin: 10.3.0 - gotrue-js: 0.9.29 jest: 29.3.1 - magic-sdk: 9.1.1 - netlify-identity-widget: 1.9.2 + msw: 0.49.1 react: 17.0.2 - supertokens-auth-react: 0.26.5 typescript: 4.7.4 languageName: unknown linkType: soft @@ -8791,11 +8794,11 @@ __metadata: linkType: hard "@supabase/gotrue-js@npm:^1.22.21": - version: 1.22.21 - resolution: "@supabase/gotrue-js@npm:1.22.21" + version: 1.24.0 + resolution: "@supabase/gotrue-js@npm:1.24.0" dependencies: cross-fetch: ^3.0.6 - checksum: b25ca1bbac177fbc3ba921686b741d86362a8745787e6d79124e00c4ddfe7dee915c6bca9d767e40173a23f4cfac892c7ab6efced22ce47d9ef5f777ec4ff361 + checksum: 83280170a36c93391290ebd94faa0c5b1eef269f5648450980f6a7ddb42f70efd54ee0e692bda57fd8ec60eb408b2e67cecbef7ce2423c1732c923d753b35429 languageName: node linkType: hard @@ -8819,11 +8822,11 @@ __metadata: linkType: hard "@supabase/storage-js@npm:^1.7.2": - version: 1.7.2 - resolution: "@supabase/storage-js@npm:1.7.2" + version: 1.7.3 + resolution: "@supabase/storage-js@npm:1.7.3" dependencies: cross-fetch: ^3.1.0 - checksum: e473e572349c495e0fd57eb5257618c95d8b5fc4fc3cf226bf5cee99a288bf753bc760f66ff8aedd2b033d18a1fae64037f63b4b8d5dafb3098a99dadbb5b00f + checksum: eda7a3b6ad1be90e7a76dd024f31e089a96d9138acbbd047948d191dc67acdd125520b69206e44cae69db405d624cc649c86a61814b25a4b6db4b04817512423 languageName: node linkType: hard @@ -9413,13 +9416,6 @@ __metadata: languageName: node linkType: hard -"@types/js-cookie@npm:2.2.6": - version: 2.2.6 - resolution: "@types/js-cookie@npm:2.2.6" - checksum: 41dba47b7470d3dbf57025f53fd77bf70e35a0a7ce414b8ac77ed088c1273e2a549a63d59bc879735a5796cc6dc8f32c04a7ad9fe137f868747a35f843c3f9d1 - languageName: node - linkType: hard - "@types/js-levenshtein@npm:^1.1.1": version: 1.1.1 resolution: "@types/js-levenshtein@npm:1.1.1" @@ -9808,15 +9804,6 @@ __metadata: languageName: node linkType: hard -"@types/react-transition-group@npm:^4.4.0": - version: 4.4.4 - resolution: "@types/react-transition-group@npm:4.4.4" - dependencies: - "@types/react": "*" - checksum: 0e593863c60550002bb7a5bf60dad719de78580017f87eadf32661d1870345a4ef22e2e37902e05d05955494f2c0cae5ef46510032005e8e969273eee0ae8519 - languageName: node - linkType: hard - "@types/react@npm:17.0.50": version: 17.0.50 resolution: "@types/react@npm:17.0.50" @@ -10699,13 +10686,6 @@ __metadata: languageName: node linkType: hard -"@xobotyi/scrollbar-width@npm:1.9.5": - version: 1.9.5 - resolution: "@xobotyi/scrollbar-width@npm:1.9.5" - checksum: 4ebc79e4f798e2a5e89a5122f8fc4a086f08a92a44ac020599c4fe20d105b7d76ba06c094260b5f386a75e7ce6f6c518d9fc295228b651296b99c4477f986ac4 - languageName: node - linkType: hard - "@xtuc/ieee754@npm:^1.2.0": version: 1.2.0 resolution: "@xtuc/ieee754@npm:1.2.0" @@ -11947,17 +11927,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-macros@npm:^2.6.1": - version: 2.8.0 - resolution: "babel-plugin-macros@npm:2.8.0" - dependencies: - "@babel/runtime": ^7.7.2 - cosmiconfig: ^6.0.0 - resolve: ^1.12.0 - checksum: 9a101e2844a800e65662b2a8d0758bdbbe500ae02d68ef6f3466ead7eaa1350e3872b97014b20bf6f3a1a46b3c9613dfac7578af6f6ae6d4eccbd68ad7b6f228 - languageName: node - linkType: hard - "babel-plugin-macros@npm:^3.0.1": version: 3.1.0 resolution: "babel-plugin-macros@npm:3.1.0" @@ -12531,7 +12500,7 @@ __metadata: languageName: node linkType: hard -"browser-tabs-lock@npm:^1.2.14, browser-tabs-lock@npm:^1.2.15": +"browser-tabs-lock@npm:^1.2.15": version: 1.2.15 resolution: "browser-tabs-lock@npm:1.2.15" dependencies: @@ -13360,15 +13329,6 @@ __metadata: languageName: node linkType: hard -"chroma-js@npm:2.1.2": - version: 2.1.2 - resolution: "chroma-js@npm:2.1.2" - dependencies: - cross-env: ^6.0.3 - checksum: f3760059b76240bab7387f335c798bbf55a4edf937534be7bc5c16ecad9b358dcfd891ca4fffa2c34742f45d5c3e96c8927c6a9906a13905da2bfa4c9ad30418 - languageName: node - linkType: hard - "chrome-trace-event@npm:^1.0.2": version: 1.0.3 resolution: "chrome-trace-event@npm:1.0.3" @@ -13426,13 +13386,6 @@ __metadata: languageName: node linkType: hard -"classnames@npm:^2.2.5, classnames@npm:^2.3.1": - version: 2.3.1 - resolution: "classnames@npm:2.3.1" - checksum: e3b832219042802464e648c41c2e8be96c2c64d2522cfa22fbb5ec088418406c61ab351a682c077c07f691c8b00c9f0ee7939b20fabc6c23da69063252a4ab89 - languageName: node - linkType: hard - "clean-css@npm:^4.2.3": version: 4.2.4 resolution: "clean-css@npm:4.2.4" @@ -14105,7 +14058,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.1.0, convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.1.0, convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": version: 1.8.0 resolution: "convert-source-map@npm:1.8.0" dependencies: @@ -14180,15 +14133,6 @@ __metadata: languageName: node linkType: hard -"copy-to-clipboard@npm:^3.2.0": - version: 3.3.1 - resolution: "copy-to-clipboard@npm:3.3.1" - dependencies: - toggle-selection: ^1.0.6 - checksum: cc38a2a07ec22b1b60c6bd1648a21178fade4d972b43e4c2570f36f8df59ca2b7e9f8a6125d271cf2927367d3ec4012c92deaf244c12cd79509244d5c7f0f4dd - languageName: node - linkType: hard - "copy-webpack-plugin@npm:11.0.0": version: 11.0.0 resolution: "copy-webpack-plugin@npm:11.0.0" @@ -14221,7 +14165,7 @@ __metadata: languageName: node linkType: hard -"core-js@npm:3.26.1, core-js@npm:^3.0.4, core-js@npm:^3.18.3, core-js@npm:^3.25.1, core-js@npm:^3.26.0, core-js@npm:^3.6.5, core-js@npm:^3.8.2": +"core-js@npm:3.26.1, core-js@npm:^3.0.4, core-js@npm:^3.25.1, core-js@npm:^3.26.0, core-js@npm:^3.6.5, core-js@npm:^3.8.2": version: 3.26.1 resolution: "core-js@npm:3.26.1" checksum: 82d36c6f54fc0349998fa7fc67d200ba272f1cd1674c6786dc17f9d259d6555fc05662044528eae73ad6e90f71d503ab5c060ad4745492ef804308209f9aec13 @@ -14289,13 +14233,6 @@ __metadata: languageName: node linkType: hard -"country-flag-icons@npm:^1.0.2": - version: 1.4.21 - resolution: "country-flag-icons@npm:1.4.21" - checksum: 7cf8e9da73b4f0fde31fefacedcb5007cbd8c5318150ed35d3ef4ee8d69099be9017e4fb153d7493f4f2abd3cdf1c40cf1a073bfda516323608ca662faf17a68 - languageName: node - linkType: hard - "cp-file@npm:^7.0.0": version: 7.0.0 resolution: "cp-file@npm:7.0.0" @@ -14451,18 +14388,6 @@ __metadata: languageName: node linkType: hard -"cross-env@npm:^6.0.3": - version: 6.0.3 - resolution: "cross-env@npm:6.0.3" - dependencies: - cross-spawn: ^7.0.0 - bin: - cross-env: src/bin/cross-env.js - cross-env-shell: src/bin/cross-env-shell.js - checksum: 0d176b91c730abb08589431970a59771148f8fbf338959f5e3aa71b866d38ba390fc67f5330306d0a37d7cb74675224d0f23086f291661b944abbf5a00bd7080 - languageName: node - linkType: hard - "cross-fetch@npm:^3.0.6, cross-fetch@npm:^3.1.0, cross-fetch@npm:^3.1.5": version: 3.1.5 resolution: "cross-fetch@npm:3.1.5" @@ -14567,16 +14492,6 @@ __metadata: languageName: node linkType: hard -"css-in-js-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "css-in-js-utils@npm:2.0.1" - dependencies: - hyphenate-style-name: ^1.0.2 - isobject: ^3.0.1 - checksum: 6696cda3ebd596fc42ff40059546786936a8cf709e00bc8dedce6cd42c2b3edb19333a5d5bba6ac35b75b58cf55c021cee7ab3ec0f13fb2cf59fbb024ba0894f - languageName: node - linkType: hard - "css-loader@npm:6.7.2": version: 6.7.2 resolution: "css-loader@npm:6.7.2" @@ -14838,7 +14753,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2, csstype@npm:^3.0.6": +"csstype@npm:^3.0.2": version: 3.0.10 resolution: "csstype@npm:3.0.10" checksum: f0fff671ab368a863946859ad96be0be66afeb83566215d6494be840ffedfaef4945b48d1b0ce1a19f9983af772e0ce38c7be91a1ad46fe7ecd641937c5a99f7 @@ -15489,16 +15404,6 @@ __metadata: languageName: node linkType: hard -"dom-helpers@npm:^5.0.1": - version: 5.2.1 - resolution: "dom-helpers@npm:5.2.1" - dependencies: - "@babel/runtime": ^7.8.7 - csstype: ^3.0.2 - checksum: f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c - languageName: node - linkType: hard - "dom-serializer@npm:^1.0.1": version: 1.3.2 resolution: "dom-serializer@npm:1.3.2" @@ -17262,13 +17167,6 @@ __metadata: languageName: node linkType: hard -"fast-shallow-equal@npm:^1.0.0": - version: 1.0.0 - resolution: "fast-shallow-equal@npm:1.0.0" - checksum: 526c393c011ab5a0ca5a36c5ea25c9730acd027503ccbec6c7825397ab9375f51f67f14c8829b4c4b1ccccede695391dd14863a15e40a37fc4af08c1440a1b66 - languageName: node - linkType: hard - "fast-text-encoding@npm:^1.0.0, fast-text-encoding@npm:^1.0.3, fast-text-encoding@npm:^1.0.6": version: 1.0.6 resolution: "fast-text-encoding@npm:1.0.6" @@ -17297,13 +17195,6 @@ __metadata: languageName: node linkType: hard -"fastest-stable-stringify@npm:^2.0.2": - version: 2.0.2 - resolution: "fastest-stable-stringify@npm:2.0.2" - checksum: abbe5ff48f13f5819e7312dbb38bae5d9960694cffd315b464df9adcd02a8fa7e9eec32c314655674c7134905c544b7a0c14b05bfbe30b3f678609bebc9fecb9 - languageName: node - linkType: hard - "fastify-plugin@npm:^3.0.1": version: 3.0.1 resolution: "fastify-plugin@npm:3.0.1" @@ -17587,13 +17478,6 @@ __metadata: languageName: node linkType: hard -"find-root@npm:^1.1.0": - version: 1.1.0 - resolution: "find-root@npm:1.1.0" - checksum: 1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa - languageName: node - linkType: hard - "find-up@npm:5.0.0, find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -19117,7 +19001,7 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2": +"hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -19487,20 +19371,6 @@ __metadata: languageName: node linkType: hard -"humps@npm:^2.0.1": - version: 2.0.1 - resolution: "humps@npm:2.0.1" - checksum: 554f3bb9de780ce833f0058f30536f87615bd75ead2008b98d900598379fe5dcd3300bdd9092d3e078d47b66fade82276974dda7151318b5de7a1d837c3abe6e - languageName: node - linkType: hard - -"hyphenate-style-name@npm:^1.0.2": - version: 1.0.4 - resolution: "hyphenate-style-name@npm:1.0.4" - checksum: b19c3e2cd1dc426f6f893752fec08140abf79058a1b6238422e45373ed81389f02e1a2ba2ef4e9b2430d4e900a0f5ba12307de82320604e81ac1b722abd2ee62 - languageName: node - linkType: hard - "iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -19742,24 +19612,6 @@ __metadata: languageName: node linkType: hard -"inline-style-prefixer@npm:^6.0.0": - version: 6.0.1 - resolution: "inline-style-prefixer@npm:6.0.1" - dependencies: - css-in-js-utils: ^2.0.0 - checksum: 02d2e0d9971a20c35ee1deba1b6a8677e1a105cdf6a17b36356c438bf1a064c99cba1e7cc97d0999c388a93b36ec08977cd0258d4e4b7be9d42cf096bba75831 - languageName: node - linkType: hard - -"input-format@npm:^0.3.6": - version: 0.3.7 - resolution: "input-format@npm:0.3.7" - dependencies: - prop-types: ^15.7.2 - checksum: b1d753f910d66047208c5520b6f6892992045d7da8a06db1ecf76ffbe5da2c47752c0c35e267c2e2d751354b191d070da7e2fef9795b69480224bba4fe1c7515 - languageName: node - linkType: hard - "inquirer@npm:^7.3.3": version: 7.3.3 resolution: "inquirer@npm:7.3.3" @@ -21304,13 +21156,6 @@ __metadata: languageName: node linkType: hard -"js-cookie@npm:^2.2.1": - version: 2.2.1 - resolution: "js-cookie@npm:2.2.1" - checksum: ee67fc0f8495d0800b851910b5eb5bf49d3033adff6493d55b5c097ca6da46f7fe666b10e2ecb13cfcaf5b88d71c205ce00a7e646de791689bfd053bbb36a376 - languageName: node - linkType: hard - "js-cookie@npm:^3.0.1": version: 3.0.1 resolution: "js-cookie@npm:3.0.1" @@ -22080,20 +21925,6 @@ __metadata: languageName: node linkType: hard -"libphonenumber-js@npm:1.9.43": - version: 1.9.43 - resolution: "libphonenumber-js@npm:1.9.43" - checksum: 99834b96a6caf8625dbc0caaf5526ed881ee1c4dc0e627c79bd6fb168014255a747911810b47657758bc24ff8c40264ed7ac78689a18c22cdf2c33f8c96fb23e - languageName: node - linkType: hard - -"libphonenumber-js@npm:^1.9.43": - version: 1.9.49 - resolution: "libphonenumber-js@npm:1.9.49" - checksum: 74af8f8bf1517fe0636c02aacd0336d3b221d3afbc5847d93686818e00c5751327468921bc7a98e10e7e17fbca23cff87a64ca1f30cc66eb126bf68395891e80 - languageName: node - linkType: hard - "lie@npm:3.1.1": version: 3.1.1 resolution: "lie@npm:3.1.1" @@ -22996,13 +22827,6 @@ __metadata: languageName: node linkType: hard -"memoize-one@npm:^5.0.0": - version: 5.2.1 - resolution: "memoize-one@npm:5.2.1" - checksum: fd22dbe9a978a2b4f30d6a491fc02fb90792432ad0dab840dc96c1734d2bd7c9cdeb6a26130ec60507eb43230559523615873168bcbe8fafab221c30b11d54c1 - languageName: node - linkType: hard - "memoizerific@npm:^1.11.3": version: 1.11.3 resolution: "memoizerific@npm:1.11.3" @@ -23650,25 +23474,6 @@ __metadata: languageName: node linkType: hard -"nano-css@npm:^5.2.1": - version: 5.3.4 - resolution: "nano-css@npm:5.3.4" - dependencies: - css-tree: ^1.1.2 - csstype: ^3.0.6 - fastest-stable-stringify: ^2.0.2 - inline-style-prefixer: ^6.0.0 - rtl-css-js: ^1.14.0 - sourcemap-codec: ^1.4.8 - stacktrace-js: ^2.0.2 - stylis: ^4.0.6 - peerDependencies: - react: "*" - react-dom: "*" - checksum: 1d3175d0a0df8b960646979f85a1f4b81ca62a6e9a91cd0a4b6c416a04feea0e49494b635eeaa4cc794ca34be1a2700919121699d909540e856709122dcf518f - languageName: node - linkType: hard - "nanoid@npm:^3.3.1, nanoid@npm:^3.3.4": version: 3.3.4 resolution: "nanoid@npm:3.3.4" @@ -23741,13 +23546,6 @@ __metadata: languageName: node linkType: hard -"netlify-identity-widget@npm:1.9.2": - version: 1.9.2 - resolution: "netlify-identity-widget@npm:1.9.2" - checksum: fcdc960f3228cdb4c1e6a1c98ca92f570d00d7914d9579712a16ef7ec72fe6d4396fbe07b24e9f9ca2fc12fd724d3193a40d97ed99c7690f209f329ae591af24 - languageName: node - linkType: hard - "new-github-issue-url@npm:0.2.1": version: 0.2.1 resolution: "new-github-issue-url@npm:0.2.1" @@ -26551,7 +26349,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.11.0, qs@npm:^6.10.0, qs@npm:^6.9.4": +"qs@npm:6.11.0, qs@npm:^6.10.0": version: 6.11.0 resolution: "qs@npm:6.11.0" dependencies: @@ -26796,7 +26594,7 @@ __metadata: languageName: node linkType: hard -"react-fast-compare@npm:^3.0.1, react-fast-compare@npm:^3.2.0": +"react-fast-compare@npm:^3.2.0": version: 3.2.0 resolution: "react-fast-compare@npm:3.2.0" checksum: 2a7d75ce9fb5da1e3c01f74a5cd592f3369a8cc8d44e93654bf147ab221f430238e8be70677e896f2bfcb96a1cb7a47a8d05d84633de764a9d57d27005a4bb9e @@ -26874,35 +26672,6 @@ __metadata: languageName: node linkType: hard -"react-phone-number-input@npm:3.1.41": - version: 3.1.41 - resolution: "react-phone-number-input@npm:3.1.41" - dependencies: - classnames: ^2.2.5 - country-flag-icons: ^1.0.2 - input-format: ^0.3.6 - libphonenumber-js: ^1.9.43 - prop-types: ^15.7.2 - peerDependencies: - react: ">=0.16.8" - react-dom: ">=0.16.8" - checksum: 1fb5750a283b21771710b9adb4859abd6f98fdd85bbf84d73a1b17340220058895857c327a4afb78058abff46e3bc726a3a17abd1438c5d9f74f6c1dafe92290 - languageName: node - linkType: hard - -"react-popper@npm:^2.2.3": - version: 2.2.5 - resolution: "react-popper@npm:2.2.5" - dependencies: - react-fast-compare: ^3.0.1 - warning: ^4.0.2 - peerDependencies: - "@popperjs/core": ^2.0.0 - react: ^16.8.0 || ^17 - checksum: 199ff9ec23670eece1c5972d48d2c5e9c28938dd610c432979fdab631a38371f8a3a5fbb9dcaeec0cff9ce9fb58b3bc1965c525de14fdb78f5e9b35f0d90f335 - languageName: node - linkType: hard - "react-refresh@npm:0.14.0": version: 0.14.0 resolution: "react-refresh@npm:0.14.0" @@ -26917,38 +26686,6 @@ __metadata: languageName: node linkType: hard -"react-select@npm:5.2.1": - version: 5.2.1 - resolution: "react-select@npm:5.2.1" - dependencies: - "@babel/runtime": ^7.12.0 - "@emotion/cache": ^11.4.0 - "@emotion/react": ^11.1.1 - "@types/react-transition-group": ^4.4.0 - memoize-one: ^5.0.0 - prop-types: ^15.6.0 - react-transition-group: ^4.3.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: a6efe7b65c9ebe77bfc9856ba763f9efa20b773f9d370ec0d9565c05b2f3aa88111d4ea282be9cb6eddaff9bd9916c53585e234b52f6e7d007a8c384997b6912 - languageName: node - linkType: hard - -"react-shadow@npm:19.0.3": - version: 19.0.3 - resolution: "react-shadow@npm:19.0.3" - dependencies: - humps: ^2.0.1 - react-use: ^15.3.3 - peerDependencies: - prop-types: ^15.0.0 - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.0.0 || ^17.0.0 - checksum: 96579ca61ddcd7d005be86f09d93236fdbd33a53b5980909cfb706ee8cad3c5af3ef681385d1b4e45d27c768b1406e275e6a722573e6c93191abe5a05e37ec70 - languageName: node - linkType: hard - "react-sizeme@npm:^3.0.1": version: 3.0.2 resolution: "react-sizeme@npm:3.0.2" @@ -26961,56 +26698,6 @@ __metadata: languageName: node linkType: hard -"react-transition-group@npm:^4.3.0": - version: 4.4.2 - resolution: "react-transition-group@npm:4.4.2" - dependencies: - "@babel/runtime": ^7.5.5 - dom-helpers: ^5.0.1 - loose-envify: ^1.4.0 - prop-types: ^15.6.2 - peerDependencies: - react: ">=16.6.0" - react-dom: ">=16.6.0" - checksum: afaf835854526065d246532714a3833a7c5fbcf21303e1479008ff6f1ec1ae44ecd151f74f357c60511a1e49de65cb9b81bf4d7858b9ee19e636b9a62a6daaa4 - languageName: node - linkType: hard - -"react-universal-interface@npm:^0.6.2": - version: 0.6.2 - resolution: "react-universal-interface@npm:0.6.2" - peerDependencies: - react: "*" - tslib: "*" - checksum: 97c32ecb7a425c3bcaa92dcf84c46146b49610d928efde9e9ee5518c475a0db942f01634dd490e4f42fcd95cc2f49657c1b96dcef96423c06f077147fe1968ab - languageName: node - linkType: hard - -"react-use@npm:^15.3.3": - version: 15.3.8 - resolution: "react-use@npm:15.3.8" - dependencies: - "@types/js-cookie": 2.2.6 - "@xobotyi/scrollbar-width": 1.9.5 - copy-to-clipboard: ^3.2.0 - fast-deep-equal: ^3.1.3 - fast-shallow-equal: ^1.0.0 - js-cookie: ^2.2.1 - nano-css: ^5.2.1 - react-universal-interface: ^0.6.2 - resize-observer-polyfill: ^1.5.1 - screenfull: ^5.0.0 - set-harmonic-interval: ^1.0.1 - throttle-debounce: ^2.1.0 - ts-easing: ^0.2.0 - tslib: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: 9679090467f65d079c684121e246e08e273c3898659755e0bf13a32f58d242d4c6531299fff310a92980041f8439d48519de6feec0c9f5b0a63d99f30876a279 - languageName: node - linkType: hard - "react@npm:17.0.2": version: 17.0.2 resolution: "react@npm:17.0.2" @@ -27650,13 +27337,6 @@ __metadata: languageName: node linkType: hard -"resize-observer-polyfill@npm:^1.5.1": - version: 1.5.1 - resolution: "resize-observer-polyfill@npm:1.5.1" - checksum: 5e882475067f0b97dc07e0f37c3e335ac5bc3520d463f777cec7e894bb273eddbfecb857ae668e6fb6881fd6f6bb7148246967172139302da50fa12ea3a15d95 - languageName: node - linkType: hard - "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -27704,7 +27384,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.22.1, resolve@npm:^1.10.0, resolve@npm:^1.11.1, resolve@npm:^1.12.0, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0, resolve@npm:^1.3.2, resolve@npm:^1.9.0": +"resolve@npm:1.22.1, resolve@npm:^1.10.0, resolve@npm:^1.11.1, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0, resolve@npm:^1.3.2, resolve@npm:^1.9.0": version: 1.22.1 resolution: "resolve@npm:1.22.1" dependencies: @@ -27727,7 +27407,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@1.22.1#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.11.1#~builtin, resolve@patch:resolve@^1.12.0#~builtin, resolve@patch:resolve@^1.13.1#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.0#~builtin, resolve@patch:resolve@^1.3.2#~builtin, resolve@patch:resolve@^1.9.0#~builtin": +"resolve@patch:resolve@1.22.1#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.11.1#~builtin, resolve@patch:resolve@^1.13.1#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.0#~builtin, resolve@patch:resolve@^1.3.2#~builtin, resolve@patch:resolve@^1.9.0#~builtin": version: 1.22.1 resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d" dependencies: @@ -27961,15 +27641,6 @@ __metadata: languageName: node linkType: hard -"rtl-css-js@npm:^1.14.0": - version: 1.15.0 - resolution: "rtl-css-js@npm:1.15.0" - dependencies: - "@babel/runtime": ^7.1.2 - checksum: ead5c5f89436af61b39c7639d39141ad291039232285176969199beb96f3267a55c5a74b5b63a05f3cbac92ff09a73bde60d33f84603ea6aaabe7934a21b4f9a - languageName: node - linkType: hard - "run-async@npm:^2.4.0": version: 2.4.1 resolution: "run-async@npm:2.4.1" @@ -28192,13 +27863,6 @@ __metadata: languageName: node linkType: hard -"screenfull@npm:^5.0.0": - version: 5.2.0 - resolution: "screenfull@npm:5.2.0" - checksum: 86fd49983e2edc153ee2e674a570c711cb0961a9cacca659309f79636ccc8ca8a0b830ea4dacdae7403a8bb7ba6affd5bcdce053aa97782961247a49bfd2ba68 - languageName: node - linkType: hard - "scrypt-js@npm:^3.0.0": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" @@ -28458,13 +28122,6 @@ __metadata: languageName: node linkType: hard -"set-harmonic-interval@npm:^1.0.1": - version: 1.0.1 - resolution: "set-harmonic-interval@npm:1.0.1" - checksum: 49014d928a62c8418507bf66ffef7066783e8fb19f76e955318bbae5a8c4b56e1a7176b370f9040ef9de51531aa522a3f96fa5c47b1534635aa577ff7c12f9c6 - languageName: node - linkType: hard - "set-immediate-shim@npm:~1.0.1": version: 1.0.1 resolution: "set-immediate-shim@npm:1.0.1" @@ -28911,14 +28568,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:0.5.6": - version: 0.5.6 - resolution: "source-map@npm:0.5.6" - checksum: beb2c5974bb58954d75e86249953d47ae16f7df1a8531abb9fcae0cd262d9fa09c2db3a134e20e99358b1adba42b6b054a32c8e16b571b3efcf6af644c329f0d - languageName: node - linkType: hard - -"source-map@npm:^0.5.0, source-map@npm:^0.5.6, source-map@npm:^0.5.7": +"source-map@npm:^0.5.0, source-map@npm:^0.5.6": version: 0.5.7 resolution: "source-map@npm:0.5.7" checksum: 904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 @@ -28939,13 +28589,6 @@ __metadata: languageName: node linkType: hard -"sourcemap-codec@npm:^1.4.8": - version: 1.4.8 - resolution: "sourcemap-codec@npm:1.4.8" - checksum: f099279fdaae070ff156df7414bbe39aad69cdd615454947ed3e19136bfdfcb4544952685ee73f56e17038f4578091e12b17b283ed8ac013882916594d95b9e6 - languageName: node - linkType: hard - "space-separated-tokens@npm:^1.0.0": version: 1.1.5 resolution: "space-separated-tokens@npm:1.1.5" @@ -29142,15 +28785,6 @@ __metadata: languageName: node linkType: hard -"stack-generator@npm:^2.0.5": - version: 2.0.5 - resolution: "stack-generator@npm:2.0.5" - dependencies: - stackframe: ^1.1.1 - checksum: 94de1664b54cd0834738bec0e0f92b76ac72fdb4f1fe63c8eee9d6a17d84b6f87be39ca40ef3abd14dffa86b4e7ae1dae9b07bda319a441c4788e4d37fc9ef75 - languageName: node - linkType: hard - "stack-utils@npm:^2.0.3": version: 2.0.5 resolution: "stack-utils@npm:2.0.5" @@ -29167,27 +28801,6 @@ __metadata: languageName: node linkType: hard -"stacktrace-gps@npm:^3.0.4": - version: 3.0.4 - resolution: "stacktrace-gps@npm:3.0.4" - dependencies: - source-map: 0.5.6 - stackframe: ^1.1.1 - checksum: eb3acc1e75593c9cc0abe081d0edc67ff0c14d860c008ca1efba17c2ab360dbf1e51ef2ca4d978907c87cfa9ac6a86efc24bd2756a3a6e4026c85811e1f4819b - languageName: node - linkType: hard - -"stacktrace-js@npm:^2.0.2": - version: 2.0.2 - resolution: "stacktrace-js@npm:2.0.2" - dependencies: - error-stack-parser: ^2.0.6 - stack-generator: ^2.0.5 - stacktrace-gps: ^3.0.4 - checksum: 9a10c222524ca03690bcb27437b39039885223e39320367f2be36e6f750c2d198ae99189869a22c255bf60072631eb609d47e8e33661e95133686904e01121ec - languageName: node - linkType: hard - "stacktracey@npm:2.1.8": version: 2.1.8 resolution: "stacktracey@npm:2.1.8" @@ -29630,13 +29243,6 @@ __metadata: languageName: node linkType: hard -"stylis@npm:4.0.13, stylis@npm:^4.0.6": - version: 4.0.13 - resolution: "stylis@npm:4.0.13" - checksum: bd567c440b4f1acf8962b1b3aa7985c4e04d7badfe1e0f1c7ee2a60912de2718973850c524001a3d52f5fc9a0e3dcd204b8bd7e2d47d4934462e9f749fd9c7bc - languageName: node - linkType: hard - "superstruct@npm:^0.15.4": version: 0.15.5 resolution: "superstruct@npm:0.15.5" @@ -29644,52 +29250,6 @@ __metadata: languageName: node linkType: hard -"supertokens-auth-react@npm:0.26.5": - version: 0.26.5 - resolution: "supertokens-auth-react@npm:0.26.5" - dependencies: - "@emotion/react": ^11.4.1 - chroma-js: 2.1.2 - libphonenumber-js: 1.9.43 - prop-types: "*" - react-phone-number-input: 3.1.41 - react-select: 5.2.1 - react-shadow: 19.0.3 - supertokens-js-override: ^0.0.4 - supertokens-web-js: ^0.2.0 - peerDependencies: - react: ">=16.8.0" - checksum: 54ba49866c6fbee8edc31d7f58be7c57b4a23e79d83293fbe3b4f692e0e41405a2a563c91cba6dc6e32addfc6afb31ba92e21c0a48a5600e30d4b17b287641e8 - languageName: node - linkType: hard - -"supertokens-js-override@npm:0.0.4, supertokens-js-override@npm:^0.0.4": - version: 0.0.4 - resolution: "supertokens-js-override@npm:0.0.4" - checksum: 75468560e2f9fa0386e38d22f80aea705342f728db877b069623d3cfe070d85977b257508a2c8d3c6439280bfd6f1c7448ba8ac312b9abba6c8927428330028e - languageName: node - linkType: hard - -"supertokens-web-js@npm:^0.2.0": - version: 0.2.1 - resolution: "supertokens-web-js@npm:0.2.1" - dependencies: - supertokens-js-override: 0.0.4 - supertokens-website: ^13.1.0 - checksum: 3722e01b38862bf358cf0ab6b7bb6cc01e667e212fdcc95502a4d0c9588f61f9ee986bc95468430dbbfd218354efc9184cd56e9d860952d4774cd1d1ec541456 - languageName: node - linkType: hard - -"supertokens-website@npm:^13.1.0": - version: 13.1.0 - resolution: "supertokens-website@npm:13.1.0" - dependencies: - browser-tabs-lock: ^1.2.14 - supertokens-js-override: ^0.0.4 - checksum: bab04ea2c5536edd4cb61e711b0d2c030ec3a8c88c983c6f1e2c58b320103512f4f4a8df282ce0f36706efa1b5dda7951e2512cc67776c3e65d602c2896e0e87 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0, supports-color@npm:^5.5.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -30110,13 +29670,6 @@ __metadata: languageName: node linkType: hard -"throttle-debounce@npm:^2.1.0": - version: 2.3.0 - resolution: "throttle-debounce@npm:2.3.0" - checksum: 41648e4cf46f935818af32ecac34f9876c618f24e300551cbe3a0ca2c5828cb8d2f9b73e6e1e2f8c64237f70fbc8c541f9b5c9114da70b33b1ed10ba4cc6b15f - languageName: node - linkType: hard - "throttle-debounce@npm:^3.0.1": version: 3.0.1 resolution: "throttle-debounce@npm:3.0.1" @@ -30328,13 +29881,6 @@ __metadata: languageName: node linkType: hard -"toggle-selection@npm:^1.0.6": - version: 1.0.6 - resolution: "toggle-selection@npm:1.0.6" - checksum: f2cf1f2c70f374fd87b0cdc8007453ba9e981c4305a8bf4eac10a30e62ecdfd28bca7d18f8f15b15a506bf8a7bfb20dbe3539f0fcf2a2c8396c1a78d53e1f179 - languageName: node - linkType: hard - "toidentifier@npm:1.0.1": version: 1.0.1 resolution: "toidentifier@npm:1.0.1" @@ -30469,13 +30015,6 @@ __metadata: languageName: node linkType: hard -"ts-easing@npm:^0.2.0": - version: 0.2.0 - resolution: "ts-easing@npm:0.2.0" - checksum: 84ec20192310c697ff890ca2e0625e131a32596a7c5956326c9632faca9037abf2dd3de4d81ac358ae9f26a6a2cfe2300f13756b26995f753d882e3d0463e327 - languageName: node - linkType: hard - "ts-invariant@npm:^0.10.3": version: 0.10.3 resolution: "ts-invariant@npm:0.10.3" @@ -31611,15 +31150,6 @@ __metadata: languageName: node linkType: hard -"warning@npm:^4.0.2": - version: 4.0.3 - resolution: "warning@npm:4.0.3" - dependencies: - loose-envify: ^1.0.0 - checksum: aebab445129f3e104c271f1637fa38e55eb25f968593e3825bd2f7a12bd58dc3738bb70dc8ec85826621d80b4acfed5a29ebc9da17397c6125864d72301b937e - languageName: node - linkType: hard - "watchpack-chokidar2@npm:^2.0.1": version: 2.0.1 resolution: "watchpack-chokidar2@npm:2.0.1"