Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: handle v2 access tokens and api keys using BearerGuard #14643

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -5,6 +5,7 @@ import { GetBookingsOutput } from "@/ee/bookings/outputs/get-bookings.output";
import { CreateScheduleInput } from "@/ee/schedules/inputs/create-schedule.input";
import { SchedulesModule } from "@/ee/schedules/schedules.module";
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
import { ApiKeyModule } from "@/modules/api-key/api-key.module";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { AvailabilitiesModule } from "@/modules/availabilities/availabilities.module";
import { PrismaModule } from "@/modules/prisma/prisma.module";
Expand All @@ -17,7 +18,7 @@ import * as request from "supertest";
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
import { withBearerAuth } from "test/utils/withBearerAuth";

import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
import { handleNewBooking } from "@calcom/platform-libraries";
Expand All @@ -40,10 +41,17 @@ describe("Bookings Endpoints", () => {
let createdBooking: Awaited<ReturnType<typeof handleNewBooking>>;

beforeAll(async () => {
const moduleRef = await withAccessTokenAuth(
const moduleRef = await withBearerAuth(
userEmail,
Test.createTestingModule({
imports: [AppModule, PrismaModule, AvailabilitiesModule, UsersModule, SchedulesModule],
imports: [
AppModule,
PrismaModule,
AvailabilitiesModule,
UsersModule,
SchedulesModule,
ApiKeyModule,
],
})
)
.overrideGuard(PermissionsGuard)
Expand Down
Expand Up @@ -4,7 +4,7 @@ import { GetBookingOutput } from "@/ee/bookings/outputs/get-booking.output";
import { GetBookingsOutput } from "@/ee/bookings/outputs/get-bookings.output";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
Expand Down Expand Up @@ -86,7 +86,7 @@ export class BookingsController {
) {}

@Get("/")
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
@Permissions([BOOKING_READ])
@ApiQuery({ name: "filters[status]", enum: Status, required: true })
@ApiQuery({ name: "limit", type: "number", required: false })
Expand Down
Expand Up @@ -2,7 +2,7 @@ import { GetBusyTimesOutput } from "@/ee/calendars/outputs/busy-times.output";
import { ConnectedCalendarsOutput } from "@/ee/calendars/outputs/connected-calendars.output";
import { CalendarsService } from "@/ee/calendars/services/calendars.service";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { UserWithProfile } from "@/modules/users/users.repository";
import { Controller, Get, UseGuards, Query } from "@nestjs/common";
import { ApiTags as DocsTags } from "@nestjs/swagger";
Expand All @@ -14,7 +14,7 @@ import { CalendarBusyTimesInput } from "@calcom/platform-types";
path: "/calendars",
version: "2",
})
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
@DocsTags("Calendars")
export class CalendarsController {
constructor(private readonly calendarsService: CalendarsService) {}
Expand Down
Expand Up @@ -20,7 +20,7 @@ import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-type
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
import { withBearerAuth } from "test/utils/withBearerAuth";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import { EventTypesByViewer, EventTypesPublic } from "@calcom/platform-libraries";
Expand Down Expand Up @@ -72,7 +72,7 @@ describe("Event types Endpoints", () => {
let user: User;

beforeAll(async () => {
const moduleRef = await withAccessTokenAuth(
const moduleRef = await withBearerAuth(
userEmail,
Test.createTestingModule({
providers: [PrismaExceptionFilter, HttpExceptionFilter],
Expand Down
Expand Up @@ -11,7 +11,7 @@ import { UpdateEventTypeOutput } from "@/ee/event-types/outputs/update-event-typ
import { EventTypesService } from "@/ee/event-types/services/event-types.service";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { UserWithProfile } from "@/modules/users/users.repository";
Expand Down Expand Up @@ -51,7 +51,7 @@ export class EventTypesController {

@Post("/")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async createEventType(
@Body() body: CreateEventTypeInput,
@GetUser() user: UserWithProfile
Expand All @@ -66,7 +66,7 @@ export class EventTypesController {

@Get("/:eventTypeId")
@Permissions([EVENT_TYPE_READ])
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async getEventType(
@Param("eventTypeId") eventTypeId: string,
@GetUser() user: UserWithProfile
Expand All @@ -85,7 +85,7 @@ export class EventTypesController {

@Get("/")
@Permissions([EVENT_TYPE_READ])
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async getEventTypes(@GetUser() user: UserWithProfile): Promise<GetEventTypesOutput> {
const eventTypes = await getEventTypesByViewer({
id: user.id,
Expand Down Expand Up @@ -141,7 +141,7 @@ export class EventTypesController {

@Patch("/:eventTypeId")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
@HttpCode(HttpStatus.OK)
async updateEventType(
@Param("eventTypeId") eventTypeId: number,
Expand All @@ -158,7 +158,7 @@ export class EventTypesController {

@Delete("/:eventTypeId")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async deleteEventType(
@Param("eventTypeId") eventTypeId: number,
@GetUser("id") userId: number
Expand Down
6 changes: 3 additions & 3 deletions apps/api/v2/src/ee/gcal/gcal.controller.ts
Expand Up @@ -5,7 +5,7 @@ import { GcalSaveRedirectOutput } from "@/ee/gcal/outputs/save-redirect.output";
import { GCalService } from "@/modules/apps/services/gcal.service";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { CredentialsRepository } from "@/modules/credentials/credentials.repository";
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
Expand Down Expand Up @@ -64,7 +64,7 @@ export class GcalController {

@Get("/oauth/auth-url")
@HttpCode(HttpStatus.OK)
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async redirect(
@Headers("Authorization") authorization: string,
@Req() req: Request
Expand Down Expand Up @@ -138,7 +138,7 @@ export class GcalController {

@Get("/check")
@HttpCode(HttpStatus.OK)
@UseGuards(AccessTokenGuard, PermissionsGuard)
@UseGuards(BearerGuard, PermissionsGuard)
@Permissions([APPS_READ])
async check(@GetUser("id") userId: number): Promise<GcalCheckOutput> {
const gcalCredentials = await this.credentialRepository.getByTypeAndUserId("google_calendar", userId);
Expand Down
4 changes: 2 additions & 2 deletions apps/api/v2/src/ee/me/me.controller.e2e-spec.ts
Expand Up @@ -14,7 +14,7 @@ import { User } from "@prisma/client";
import * as request from "supertest";
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
import { withBearerAuth } from "test/utils/withBearerAuth";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import { UserResponse } from "@calcom/platform-types";
Expand All @@ -31,7 +31,7 @@ describe("Me Endpoints", () => {
let user: User;

beforeAll(async () => {
const moduleRef = await withAccessTokenAuth(
const moduleRef = await withBearerAuth(
userEmail,
Test.createTestingModule({
imports: [
Expand Down
4 changes: 2 additions & 2 deletions apps/api/v2/src/ee/me/me.controller.ts
Expand Up @@ -3,7 +3,7 @@ import { UpdateMeOutput } from "@/ee/me/outputs/update-me.output";
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository";
Expand All @@ -17,7 +17,7 @@ import { userSchemaResponse } from "@calcom/platform-types";
path: "/me",
version: "2",
})
@UseGuards(AccessTokenGuard, PermissionsGuard)
@UseGuards(BearerGuard, PermissionsGuard)
@DocsTags("Me")
export class MeController {
constructor(
Expand Down
4 changes: 2 additions & 2 deletions apps/api/v2/src/ee/provider/provider.controller.ts
@@ -1,7 +1,7 @@
import { ProviderVerifyAccessTokenOutput } from "@/ee/provider/outputs/verify-access-token.output";
import { ProviderVerifyClientOutput } from "@/ee/provider/outputs/verify-client.output";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository";
import { UserWithProfile } from "@/modules/users/users.repository";
import {
Expand Down Expand Up @@ -44,7 +44,7 @@ export class CalProviderController {

@Get("/:clientId/access-token")
@HttpCode(HttpStatus.OK)
@UseGuards(AccessTokenGuard)
@UseGuards(BearerGuard)
async verifyAccessToken(
@Param("clientId") clientId: string,
@GetUser() user: UserWithProfile
Expand Down
Expand Up @@ -17,7 +17,7 @@ import { User } from "@prisma/client";
import * as request from "supertest";
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
import { withBearerAuth } from "test/utils/withBearerAuth";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import { UpdateScheduleInput } from "@calcom/platform-types";
Expand All @@ -38,7 +38,7 @@ describe("Schedules Endpoints", () => {
const defaultAvailabilityEndTime = "1970-01-01T17:00:00.000Z";

beforeAll(async () => {
const moduleRef = await withAccessTokenAuth(
const moduleRef = await withBearerAuth(
userEmail,
Test.createTestingModule({
imports: [
Expand Down
Expand Up @@ -7,7 +7,7 @@ import { UpdateScheduleOutput } from "@/ee/schedules/outputs/update-schedule.out
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { UserWithProfile } from "@/modules/users/users.repository";
import {
Expand All @@ -33,7 +33,7 @@ import { CreateScheduleInput } from "../inputs/create-schedule.input";
path: "schedules",
version: "2",
})
@UseGuards(AccessTokenGuard, PermissionsGuard)
@UseGuards(BearerGuard, PermissionsGuard)
@DocsTags("Schedules")
export class SchedulesController {
constructor(private readonly schedulesService: SchedulesService) {}
Expand Down
16 changes: 4 additions & 12 deletions apps/api/v2/src/modules/auth/auth.module.ts
@@ -1,8 +1,7 @@
import { ApiKeyModule } from "@/modules/api-key/api-key.module";
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
import { BearerGuard } from "@/modules/auth/guards/bearer/bearer.guard";
import { NextAuthGuard } from "@/modules/auth/guards/next-auth/next-auth.guard";
import { AccessTokenStrategy } from "@/modules/auth/strategies/access-token/access-token.strategy";
import { ApiKeyAuthStrategy } from "@/modules/auth/strategies/api-key-auth/api-key-auth.strategy";
import { BearerStrategy } from "@/modules/auth/strategies/bearer/bearer.strategy";
import { NextAuthStrategy } from "@/modules/auth/strategies/next-auth/next-auth.strategy";
import { MembershipsModule } from "@/modules/memberships/memberships.module";
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
Expand All @@ -13,14 +12,7 @@ import { PassportModule } from "@nestjs/passport";

@Module({
imports: [PassportModule, ApiKeyModule, UsersModule, MembershipsModule, TokensModule],
providers: [
ApiKeyAuthStrategy,
NextAuthGuard,
NextAuthStrategy,
AccessTokenGuard,
AccessTokenStrategy,
OAuthFlowService,
],
exports: [NextAuthGuard, AccessTokenGuard],
providers: [NextAuthGuard, NextAuthStrategy, BearerGuard, BearerStrategy, OAuthFlowService],
exports: [NextAuthGuard, BearerGuard],
})
export class AuthModule {}
@@ -1,6 +1,6 @@
import { AuthGuard } from "@nestjs/passport";

export class AccessTokenGuard extends AuthGuard("access-token") {
export class BearerGuard extends AuthGuard("bearer") {
constructor() {
super();
}
Expand Down
@@ -1,4 +1,5 @@
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
import { isApiKey } from "@/modules/auth/strategies/bearer/bearer.strategy";
import { TokensRepository } from "@/modules/tokens/tokens.repository";
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
Expand All @@ -11,19 +12,18 @@ export class PermissionsGuard implements CanActivate {

async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredPermissions = this.reflector.get(Permissions, context.getHandler());
const request = context.switchToHttp().getRequest();
const bearerToken = request.get("Authorization")?.replace("Bearer ", "");

if (!requiredPermissions?.length || !Object.keys(requiredPermissions)?.length) {
if (!requiredPermissions?.length || !Object.keys(requiredPermissions)?.length || isApiKey(bearerToken)) {
return true;
}

const request = context.switchToHttp().getRequest();
const accessToken = request.get("Authorization")?.replace("Bearer ", "");

if (!accessToken) {
if (!bearerToken) {
return false;
}

const oAuthClientPermissions = await this.getOAuthClientPermissions(accessToken);
const oAuthClientPermissions = await this.getOAuthClientPermissions(bearerToken);

if (!oAuthClientPermissions) {
return false;
Expand Down

This file was deleted.