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/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-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/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..f1cfac31771d --- /dev/null +++ b/packages/auth-providers/clerk/api/package.json @@ -0,0 +1,40 @@ +{ + "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", + "core-js": "3.26.1" + }, + "devDependencies": { + "@babel/cli": "7.19.3", + "@babel/core": "7.20.5", + "@types/aws-lambda": "8.10.107", + "jest": "29.3.1", + "typescript": "4.7.4" + }, + "peerDependencies": { + "@clerk/clerk-sdk-node": "3.9.2", + "@redwoodjs/api": "3.2.0" + }, + "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 100% rename from packages/auth-providers-api/src/clerk/decoder.ts rename to packages/auth-providers/clerk/api/src/decoder.ts 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..a925964c5e44 --- /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": "../../../auth" }] +} 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..ae4f3bc966d7 --- /dev/null +++ b/packages/auth-providers/clerk/setup/src/index.ts @@ -0,0 +1 @@ +export * as setupAuthClerkCommand from './setup' diff --git a/packages/auth-providers-setup/src/clerk/setup.ts b/packages/auth-providers/clerk/setup/src/setup.ts similarity index 100% rename from packages/auth-providers-setup/src/clerk/setup.ts rename to packages/auth-providers/clerk/setup/src/setup.ts 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 100% 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 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..a6cd389a0ef7 --- /dev/null +++ b/packages/auth-providers/clerk/web/package.json @@ -0,0 +1,43 @@ +{ + "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", + "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": { + "@clerk/clerk-js": "3.17.0", + "@clerk/clerk-react": "3.5.1", + "@redwoodjs/auth": "3.2.0" + }, + "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/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..35536f5436db --- /dev/null +++ b/packages/auth-providers/dbAuth/api/package.json @@ -0,0 +1,47 @@ +{ + "name": "@redwoodjs/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", + "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", + "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" + }, + "peerDependencies": { + "@redwoodjs/api": "3.2.0" + }, + "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 100% rename from packages/auth-providers-api/src/dbAuth/index.ts rename to packages/auth-providers/dbAuth/api/src/index.ts 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..a4ca04bf33f2 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/package.json @@ -0,0 +1,46 @@ +{ + "name": "@redwoodjs/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" + }, + "peerDependencies": { + "@redwoodjs/auth": "3.2.0" + }, + "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..733712750eb8 --- /dev/null +++ b/packages/auth-providers/dbAuth/setup/src/index.ts @@ -0,0 +1 @@ +export * as setupAuthDbAuthCommand from './setup' diff --git a/packages/auth-providers-setup/src/dbAuth/setup.ts b/packages/auth-providers/dbAuth/setup/src/setup.ts similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/setup.ts rename to packages/auth-providers/dbAuth/setup/src/setup.ts 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/templates/api/functions/auth.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/api/functions/auth.ts.template similarity index 100% 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 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 100% 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 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-setup/src/dbAuth/templates/web/auth.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.ts.template similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/templates/web/auth.ts.template rename to packages/auth-providers/dbAuth/setup/src/templates/web/auth.ts.template diff --git a/packages/auth-providers-setup/src/dbAuth/templates/web/auth.webAuthn.ts.template b/packages/auth-providers/dbAuth/setup/src/templates/web/auth.webAuthn.ts.template similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/templates/web/auth.webAuthn.ts.template rename to packages/auth-providers/dbAuth/setup/src/templates/web/auth.webAuthn.ts.template diff --git a/packages/auth-providers-setup/src/dbAuth/webAuthn.setupData.ts b/packages/auth-providers/dbAuth/setup/src/webAuthn.setupData.ts similarity index 100% rename from packages/auth-providers-setup/src/dbAuth/webAuthn.setupData.ts rename to packages/auth-providers/dbAuth/setup/src/webAuthn.setupData.ts 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..e20dfe05be5f --- /dev/null +++ b/packages/auth-providers/dbAuth/web/package.json @@ -0,0 +1,41 @@ +{ + "name": "@redwoodjs/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" + ], + "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", + "@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": { + "@redwoodjs/auth": "3.2.0" + }, + "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-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/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..643468544303 --- /dev/null +++ b/packages/auth-providers/supabase/api/package.json @@ -0,0 +1,41 @@ +{ + "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", + "@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-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..2769cf70833d --- /dev/null +++ b/packages/auth-providers/supabase/setup/src/index.ts @@ -0,0 +1 @@ +export * as setupAuthSupabaseCommand from './setup' diff --git a/packages/auth-providers-setup/src/supabase/setup.ts b/packages/auth-providers/supabase/setup/src/setup.ts similarity index 100% rename from packages/auth-providers-setup/src/supabase/setup.ts rename to packages/auth-providers/supabase/setup/src/setup.ts 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 100% 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 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..25e7c2ab45cd --- /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", + "@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": { + "@redwoodjs/auth": "3.2.0", + "@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..ae0b464f3dbc --- /dev/null +++ b/packages/auth-providers/supertokens/api/package.json @@ -0,0 +1,41 @@ +{ + "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", + "@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-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..a925964c5e44 --- /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": "../../../auth" }] +} 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..216bc26c9a65 --- /dev/null +++ b/packages/auth-providers/supertokens/setup/src/index.ts @@ -0,0 +1 @@ +export * as setupAuthSupertokensCommand from './setup' diff --git a/packages/auth-providers-setup/src/supertokens/setup.ts b/packages/auth-providers/supertokens/setup/src/setup.ts similarity index 100% rename from packages/auth-providers-setup/src/supertokens/setup.ts rename to packages/auth-providers/supertokens/setup/src/setup.ts 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 100% 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 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..40f57ef8c378 --- /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", + "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": { + "@redwoodjs/auth": "3.2.0", + "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/yarn.lock b/yarn.lock index 73a7306c0f73..b1eecba1e577 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6577,6 +6577,58 @@ __metadata: 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 + "@types/aws-lambda": 8.10.107 + core-js: 3.26.1 + jest: 29.3.1 + typescript: 4.7.4 + peerDependencies: + "@clerk/clerk-sdk-node": 3.9.2 + "@redwoodjs/api": 3.2.0 + 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 + "@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-js": 3.17.0 + "@clerk/clerk-react": 3.5.1 + "@redwoodjs/auth": 3.2.0 + languageName: unknown + linkType: soft + "@redwoodjs/auth-custom-setup@workspace:packages/auth-providers/custom/setup": version: 0.0.0-use.local resolution: "@redwoodjs/auth-custom-setup@workspace:packages/auth-providers/custom/setup" @@ -6701,58 +6753,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 +6788,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 +6800,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 + "@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 + +"@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 + "@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: + "@redwoodjs/auth": 3.2.0 + "@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 + "@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 + +"@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 + "@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: + "@redwoodjs/auth": 3.2.0 + supertokens-auth-react: 0.26.5 languageName: unknown linkType: soft @@ -7042,6 +7143,70 @@ __metadata: languageName: unknown linkType: soft +"@redwoodjs/dbauth-api@workspace:packages/auth-providers/dbAuth/api": + version: 0.0.0-use.local + resolution: "@redwoodjs/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 + peerDependencies: + "@redwoodjs/api": 3.2.0 + languageName: unknown + linkType: soft + +"@redwoodjs/dbauth-setup@workspace:packages/auth-providers/dbAuth/setup": + version: 0.0.0-use.local + resolution: "@redwoodjs/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 + peerDependencies: + "@redwoodjs/auth": 3.2.0 + languageName: unknown + linkType: soft + +"@redwoodjs/dbauth-web@workspace:packages/auth-providers/dbAuth/web": + version: 0.0.0-use.local + resolution: "@redwoodjs/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 + "@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: + "@redwoodjs/auth": 3.2.0 + languageName: unknown + linkType: soft + "@redwoodjs/eslint-config@3.2.0, @redwoodjs/eslint-config@workspace:packages/eslint-config": version: 0.0.0-use.local resolution: "@redwoodjs/eslint-config@workspace:packages/eslint-config" @@ -31835,6 +32000,12 @@ __metadata: languageName: node linkType: hard +"webAuthn-0dbb62@workspace:packages/auth-providers/dbAuth/web/webAuthn": + version: 0.0.0-use.local + resolution: "webAuthn-0dbb62@workspace:packages/auth-providers/dbAuth/web/webAuthn" + languageName: unknown + linkType: soft + "webcrypto-core@npm:^1.7.4": version: 1.7.5 resolution: "webcrypto-core@npm:1.7.5"