소스코드

https://github.com/LDK1009/Supabase-FCM-Push-Notification

 

GitHub - LDK1009/Supabase-FCM-Push-Notification: Next.js + Supabase + FCM 을 활용한 푸쉬 알림 기능 소스코드 저장

Next.js + Supabase + FCM 을 활용한 푸쉬 알림 기능 소스코드 저장소입니다. - LDK1009/Supabase-FCM-Push-Notification

github.com

 

배경

문제는 Supabase 푸시 알림 기능 구현 중 FCM 토큰 발급 과정에서 발생했습니다.

Supabase 푸시 알림 기능 구현을 위해서는 FCM(Firebase Cloude Message)을 활용해 FCM 토큰을 발급 받아야했습니다.

FCM 토큰 발급 코드를 작성하고 개발 서버 환경에서 테스트 중에 문제가 발생했습니다.

개발 서버를 실행시킨 로컬 컴퓨터 환경에서 http://localhost:3000으로 접속해 테스트 시 정상적으로 토큰이 발급되었습니다.

하지만 모바일 환경 테스트를 위해 모바일 기기 브라우저에서 PC의 IP주소(ex : http://172.30.1.66:3000)로 접속해 테스트하면 아래 오류 코드와 함께 오류가 발생했습니다.

결론적으로, 필자는 위 문제가 서비스워커 등록 여부 + FCM 보안 컨텍스트와 관련이 있다고 판단하였습니다.

 

핵심 개념

1. 보안 컨텍스트는 HTTPS 또는 localhost와 같은 보안된 환경에서만 동작하는 웹 환경입니다.

2. 서비스 워커는 보안 컨텍스트에서만 등록 가능합니다.

3. FCM은 보안 컨텍스트에서만 작동합니다.

4. 브라우저는 localhost를 보안 컨텍스트로 분류합니다.

5. Next.js 개발 서버는 기본적으로 HTTP를 적용합니다.

6. Vercel은 모든 배포에 자동으로 HTTPS를 적용합니다.

 

트러블슈팅

필자가 오류 해결을 위해 시도한 케이스들과 각 케이스별 오류 발생 원인에 대해 설명하겠습니다. 

 

1. 개발 서버를 HTTP로 실행 

npm run dev

위 명령어를 터미널에 입력하여 개발 서버를 실행하였습니다.

이 때, 개발 서버는 HTTP를 적용합니다. (# 핵심 개념 3)

 

개발 서버에 HTTP가 적용되었기 때문에 서비스 워커 등록이 불가합니다. (# 핵심개념 2)

하지만, 로컬호스트로 접속 시 보안 컨텍스트로 분류되어 서비스 워커 등록이 가능합니다.(# 핵심개념 5)

 

따라서, 로컬호스트(http://localhost:3000)로 접속 시 서비스 워커가 정상적으로 등록되어 오류가 발생하지 않습니다.

하지만 IP 주소(ex : http://172.30.1.66:3000)로 접속 시 서비스 워커가 등록되지 않아 오류가 발생합니다.

 

오류 메세지
1.
Error: Cannot read properties of undefined (reading 'addEventListener')

2. FirebaseError: Messaging: This browser doesn't support the API's required to use the Firebase SDK. (messaging/unsupported-browser).

1번 오류는 서비스 워커 등록이 불가능하여 navigator.serviceWorker를 사용할 수 없어 발생합니다.

2번 오류는 서비스 워커 등록 불가 및 HTTP 환경으로 인해 FCM API를 사용할 수 없어 발생합니다.

 

참고코드
// 서비스 워커 등록 여부 확인
if (!window.navigator.serviceWorker) {
    alert("서비스 워커 등록 오류");
    return;
}

 

2. 개발 서버를 HTTPS로 실행

npx next dev --experimental-https

위 명령어를 터미널에 입력하여 개발 서버를 실행하였습니다.

이 때, 개발 서버는 HTTPS를 적용합니다.

 

개발 서버에 HTTPS가 적용되었기 때문에 서비스 워커 등록이 가능합니다. (# 핵심개념 1, 2)

로컬호스트(http://localhost:3000) 로 접속 시 FCM 토큰이 정상적으로 발급됩니다.(# 핵심개념 3)

하지만 IP주소(ex : http://172.30.1.66:3000)로 접속 시 FCM API 사용이 거부되어 FCM 토큰이 정상적으로 발급되지 않습니다.

 

이는 Next.js 개발 서버가 HTTPS로 실행되지만, 자체 서명된 인증서(self-signed certificate)를 사용하기 때문입니다.

자체 서명된 인증서는 보통 CN=localhost 로 설정됩니다.

브라우저는 URL의 도메인과 인증서의 CN이 일치하지 않으면 인증서를 신뢰하지 않으며, SSL 오류를 발생시킵니다.

 

따라서, 로컬호스트(http://localhost:3000)로 접속하면 URL 도메인(localhost)과 자체 서명 인증서의 도메인(localhost)이 일치하여 FCM API 사용이 허용되고 FCM 토큰이 정상적으로 발급됩니다.

하지만, IP 주소(https://172.30.1.66:3000)로 접속하면 URL 도메인(172.30.1.66)과 자체 서명 인증서의 CN(localhost)이 불일치하여 브라우저가 SSL 인증서를 신뢰하지 않습니다.

이로 인해 보안 컨텍스트에서 제외되며, FCM API 사용이 거부되고 FCM 토큰 발급이 실패합니다.

 

오류 메세지
FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('https://172.30.1.66:3000/firebase-cloud-messaging-push-scope') with script ('https://172.30.1.66:3000/firebase-messaging-sw.js'): An SSL certificate error occurred when fetching the script. (messaging/failed-service-worker-registration).

이 오류는 SSL 인증서 문제로 인해 IP 주소로 접속 시 서비스 워커를 등록할 수 없으며, 그로 인해 FCM 메시징 서비스가 정상적으로 작동하지 않는다는 의미입니다.

 

해결방법

위에서 살펴본 오류들의 원인은 아래와 같습니다.

1. HTTP 개발 서버 환경으로 인한 서비스 워커 등록 불가 -> FCM API 사용 불가

2. 개발 서버에서 자체 서명된 인증서 사용으로 인한 SSL 오류 -> FCM API 사용 거부 -> FCM 토큰 발급 불가

 

따라서, 아래 해결 방법을 통해 위 원인들을 해결하면 정상적으로 FCM 토큰을 발급받을 수 있습니다.

1. HTTPS 환경 적용

2. 유효한 SSL 인증서 사용

 

그렇다면 위 2가지 해결 방법을 어떻게 적용할 수 있을까요?

다행히, 배포 플랫폼(ex : Vercel, Netlify ...)을 사용하면 이를 아주 간단하게 적용할 수 있습니다.

대부분의 배포 플랫폼에서는 자동으로 SSL 인증서를 발급하여 HTTPS 환경을 보장하며 필자는 Vercel을 통해 배포하였습니다.

결과적으로 Vercel에 배포 후 테스트 결과 서비스워커 등록 및 FCM 토큰 발급이 정상적으로 작동하였습니다.

끝.