diff --git a/README.md b/README.md index ead6c04623..8a01433f90 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,13 @@ -<<<<<<< HEAD # Cal.com Public API (Enterprise Only) -======= -# Public API for Cal.com ## This will be the new public enterprise-only API -It will be a REST API for now, we might want to look into adding a GraphQL endpoint way down the roadmap if it makes sense. For now we think REST should cover what developers need. +This is the public REST api for cal.com. ## NextJS + TypeScript It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. -## NextAuth - -Using the new next-auth middleware getToken and getSession for our API auth and any other middleware check we might want to do like user role. enterprise status, api req limit, etc. - -The idea is to leverage current `Session` accessToken. next-auth reads the Authorization Header and if it contains a valid JWT Bearer Token, it decodes it. - -We'll also need the EmailProvider (to expose VerificationTokens generation) and prisma adapter (to connect with the database) -We will extend it to also be valids PAT's with longer than web auth sessions expiryDates (maybe never expire). - ## No react It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like: @@ -28,79 +16,10 @@ It doesn't have react or react-dom as a dependency, and will only be used by a r - `api.cal.com/v1` - `app.cal.com/api/v1/` -## Example - -HTTP Request (Use Paw.app/postman/postwoman/hoppscotch) - -``` -POST /api/jwt HTTP/1.1 -authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ -``` - -or with cURL - -``` -curl -X "POST" "http://localhost:3002/api/jwt" \ - -H 'authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ' -``` - -Returns: - -```{ - "name": null, - "email": "m@n.es", - "sub": "cl032mhik0006w4ylrtay2t3f", - "iat": 1645894473, - "exp": 1648486473, - "jti": "af1c04f2-09a8-45b5-a6f0-c35eea9efa9b", - "userRole": "admin" -} -``` - ## API Endpoint Validation The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. - -## Testing - - - - -/event-types -GET -/teams -teams/join - -GET / PATCH / PUT /users/:id - -/users/new -POST -/event-types -/bookings -/availabilties -/schedules - -## Users - -GET /users : Get all users you're an owner / team manager of. Requires Auth. -POST /users : Create a new user -GET /users/{id} : Get the user information identified by "id" -PUT /users/{id} : Update the user information identified by "id" -DELETE /users/{id} : Delete user by "id" - -## Event Types - -/event-types -GET /event-types : Get all event-types -POST /event-types : Create a new user -GET /event-types/{id} : Get the user information identified by "id" -PUT /event-types/{id} : Update the user information identified by "id" -DELETE /event-types/{id} : Delete user by "id" - -## Bookings - -/bookings ->>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks) +## Testing with Jest + node-mocks-http \ No newline at end of file diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts deleted file mode 100644 index b7524ad529..0000000000 --- a/pages/api/_middleware.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { getToken } from "next-auth/jwt"; -import { NextRequest, NextResponse } from "next/server"; - -export async function middleware(req: NextApiRequest) { - // return early if url isn't supposed to be protected - // if (!req.url.includes("/protected-url")) { - // return NextResponse.next() - // } - console.log(req.headers); - const session = await getToken({ req, secret: process.env.SECRET }); - // You could also check for any property on the session object, - // like role === "admin" or name === "John Doe", etc. - if (!session) { - return NextResponse.redirect("https://localhost:3002/unauthorized"); - } - - // If user is authenticated, continue. - return NextResponse.next(); -} diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts deleted file mode 100644 index d3d2886b06..0000000000 --- a/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,82 +0,0 @@ -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import { PrismaClient } from "@prisma/client"; -import NextAuth, { NextAuthOptions } from "next-auth"; -import EmailProvider from "next-auth/providers/email"; - -// FIXME: not working when importing prisma directly from our project -// import prisma from "@calcom/prisma"; -const prisma = new PrismaClient(); - -// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app - -export const authOptions: NextAuthOptions = { - // For more information on each option (and a full list of options) go to - // https://next-auth.js.org/configuration/options - adapter: PrismaAdapter(prisma), - // https://next-auth.js.org/configuration/providers - providers: [ - EmailProvider({ - maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only - // sendVerificationRequest, - }), - ], - secret: process.env.NEXTAUTH_SECRET, - session: { - // Use JSON Web Tokens for session instead of database sessions. - // This option can be used with or without a database for users/accounts. - // Note: `strategy` should be set to 'jwt' if no database is used. - - // TODO: Do we want to move 'database' sessions at some point? - strategy: "jwt", - // Seconds - How long until an idle session expires and is no longer valid. - // maxAge: 30 * 24 * 60 * 60, // 30 days - - // Seconds - Throttle how frequently to write to database to extend a session. - // Use it to limit write operations. Set to 0 to always update the database. - // Note: This option is ignored if using JSON Web Tokens - // updateAge: 24 * 60 * 60, // 24 hours - }, - - // JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session - // option is set - or by default if no database is specified. - // https://next-auth.js.org/configuration/options#jwt - jwt: { - // A secret to use for key generation (you should set this explicitly) - secret: process.env.SECRET, - // Set to true to use encryption (default: false) - // encryption: true, - // You can define your own encode/decode functions for signing and encryption - // if you want to override the default behaviour. - // encode: async ({ secret, token, maxAge }) => {}, - // decode: async ({ secret, token, maxAge }) => {}, - }, - // https://next-auth.js.org/configuration/pages - // NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com - pages: { - signIn: "/", // Displays signin buttons - signOut: "/", // Displays form with sign out button - error: "/", // Error code passed in query string as ?error= - verifyRequest: "/", // Used for check email page - newUser: "/", // If set, new users will be directed here on first sign in - }, - - // Callbacks are asynchronous functions you can use to control what happens - // when an action is performed. - // https://next-auth.js.org/configuration/callbacks - - callbacks: { - // async signIn({ user, account, profile, email, credentials }) { return true }, - // async redirect({ url, baseUrl }) { return baseUrl }, - // async session({ session, token, user }) { return session }, - // FIXME: add a custom jwt callback, that is stored outside next-auth - // and can be reused to generate valid Personal Access Tokens for the API. - // async jwt({ token, user, account, profile, isNewUser }) { return token } - }, - - // Events are useful for logging - // https://next-auth.js.org/configuration/events - - // Enable debug messages in the console if you are having problems - debug: false, -}; -export default NextAuth(authOptions); diff --git a/pages/api/jwt.ts b/pages/api/jwt.ts deleted file mode 100644 index c480ea6947..0000000000 --- a/pages/api/jwt.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next" -import { getToken } from "next-auth/jwt"; - -const secret = process.env.NEXTAUTH_SECRET; -export default async function jwt(req: NextApiRequest, res: NextApiResponse) { - const token = await getToken({ req, secret }); - res.send(JSON.stringify(token, null, 2)); -} diff --git a/pages/api/protected.ts b/pages/api/protected.ts deleted file mode 100644 index e4c71db792..0000000000 --- a/pages/api/protected.ts +++ /dev/null @@ -1,19 +0,0 @@ -// This is an example of how to read a JSON Web Token from an API route -import type { NextApiRequest, NextApiResponse } from "next"; -import { getToken } from "next-auth/jwt"; - -const secret = process.env.NEXTAUTH_SECRET; - -export default async function jwt(req: NextApiRequest, res: NextApiResponse) { - const token = await getToken({ req, secret, raw: false }); - if (token) { - res.send({ - content: "This is protected content. You can access this content because you are signed in.", - token, - }); - } else { - res.send({ - error: "You must be signed in to view the protected content on this page.", - }); - } -} diff --git a/pages/api/session.ts b/pages/api/session.ts deleted file mode 100644 index cd3df045ec..0000000000 --- a/pages/api/session.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { getServerSession } from "next-auth"; - -import { authOptions } from "./auth/[...nextauth]"; - -export default async function session(req: NextApiRequest, res: NextApiResponse) { - const session = await getServerSession({ req, res }, authOptions); - /* ... */ - if (session) { - res.send(JSON.stringify(session, null, 2)); - } else { - res.end(); - } -} diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts deleted file mode 100644 index 543d94f7d1..0000000000 --- a/src/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,33 +0,0 @@ -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import NextAuth from "next-auth"; -import EmailProvider from "next-auth/providers/email"; - -import { defaultCookies } from "@calcom/lib/default-cookies"; -import { serverConfig } from "@calcom/lib/serverConfig"; -import prisma from "@calcom/prisma"; - -const WEBSITE_BASE_URL = process.env.WEBSITE_BASE_URL || ""; - - -export default NextAuth({ - adapter: PrismaAdapter(prisma), - providers: [ - EmailProvider({ - maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only - // sendVerificationRequest, - }), - ], - secret: process.env.SECRET, - cookies: defaultCookies(WEBSITE_BASE_URL?.startsWith("https://")), - session: { - strategy: "jwt", - }, - jwt: { - // A secret to use for key generation (you should set this explicitly) - secret: process.env.SECRET, - // Set to true to use encryption (default: false) - // encryption: true, - }, - // Enable debug messages in the console if you are having problems - debug: true, -});