diff --git a/src/application.module.ts b/src/application.module.ts index 5b437a9..056d26c 100644 --- a/src/application.module.ts +++ b/src/application.module.ts @@ -2,6 +2,7 @@ import { Logger, Module, OnApplicationShutdown } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; import { HealthCheckHttpController } from "./shared-kernel/use-cases/health-check/http.controller.js"; import { SignInWithOAuthProviderHttpController } from "@identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.js"; +import { SignInWithOAuthProviderUseCase } from "@identity-and-access/use-cases/sign-in-with-oauth-provider/use-case.js"; @Module({ imports: [ConfigModule.forRoot()], @@ -9,6 +10,7 @@ import { SignInWithOAuthProviderHttpController } from "@identity-and-access/use- HealthCheckHttpController, SignInWithOAuthProviderHttpController, ], + providers: [SignInWithOAuthProviderUseCase], }) export class ApplicationModule implements OnApplicationShutdown { private readonly logger = new Logger(ApplicationModule.name); diff --git a/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.e2e.spec.ts b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.e2e.spec.ts index d065edc..a96e140 100644 --- a/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.e2e.spec.ts +++ b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.e2e.spec.ts @@ -1,16 +1,20 @@ import { describe, expect, it } from "vitest"; describe("SignInWithOAuthProviderUseCase", () => { - it("should initiate the OAuth flow by redirecting to the IDP's authorization endpoint", async () => { - // Act - const response = await fetch( - "http://localhost:8080/identity-and-access/oauth/google" - ); + it.each` + provider | expectedRedirectUrl + ${"google"} | ${"https://accounts.google.com/v3/signin/identifier"} + `( + "should initiate the $provider OAuth flow by redirecting to the IDP's authorization endpoint", + async ({ provider, expectedRedirectUrl }) => { + // Act + const response = await fetch( + `http://localhost:8080/identity-and-access/oauth/${provider}` + ); - // Assert - expect(response.redirected).toBe(true); - expect(response.url).toMatch( - "https://accounts.google.com/v3/signin/identifier" - ); - }); + // Assert + expect(response.redirected).toBe(true); + expect(response.url).toMatch(expectedRedirectUrl); + } + ); }); diff --git a/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.ts b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.ts index 031e8f3..36d8d9d 100644 --- a/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.ts +++ b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/http.controller.ts @@ -3,29 +3,19 @@ import { Get, HttpCode, HttpStatus, + Param, Redirect, } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; +import { SignInWithOAuthProviderUseCase } from "./use-case.js"; @Controller() export class SignInWithOAuthProviderHttpController { - constructor(private readonly config: ConfigService) {} + constructor(private readonly useCase: SignInWithOAuthProviderUseCase) {} - @Get("/identity-and-access/oauth/google") + @Get("/identity-and-access/oauth/:provider") @HttpCode(HttpStatus.PERMANENT_REDIRECT) @Redirect() - async signInWithGoogle() { - const baseAuthorizationUrl = `https://accounts.google.com/o/oauth2/v2/auth`; - const authorizationUrlParameters = new URLSearchParams({ - client_id: await this.config.getOrThrow("OAUTH_GOOGLE_CLIENT_ID"), - redirect_uri: - "http://localhost:8080/identity-and-access/oauth/google/callback", - response_type: "code", - scope: "email", - }); - - return { - url: `${baseAuthorizationUrl}?${authorizationUrlParameters}`, - }; + async signInWithGoogle(@Param("provider") provider: string) { + return await this.useCase.execute({ provider }); } } diff --git a/src/identity-and-access/use-cases/sign-in-with-oauth-provider/use-case.ts b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/use-case.ts new file mode 100644 index 0000000..2e29f22 --- /dev/null +++ b/src/identity-and-access/use-cases/sign-in-with-oauth-provider/use-case.ts @@ -0,0 +1,34 @@ +import { Injectable, NotImplementedException } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; + +@Injectable() +export class SignInWithOAuthProviderUseCase { + constructor(private readonly config: ConfigService) {} + + async execute(command: SignInWithOAuthProviderCommand) { + if (command.provider !== "google") { + throw new NotImplementedException(); + } + + return this.handleSignInWithGoogle(); + } + + async handleSignInWithGoogle() { + const baseAuthorizationUrl = `https://accounts.google.com/o/oauth2/v2/auth`; + const authorizationUrlParameters = new URLSearchParams({ + client_id: await this.config.getOrThrow("OAUTH_GOOGLE_CLIENT_ID"), + redirect_uri: + "http://localhost:8080/identity-and-access/oauth/google/callback", + response_type: "code", + scope: "email", + }); + + return { + url: `${baseAuthorizationUrl}?${authorizationUrlParameters}`, + }; + } +} + +type SignInWithOAuthProviderCommand = { + provider: string; +};