커스텀 이메일 작업 핸들러 만들기

사용자의 이메일 주소 업데이트나 비밀번호 재설정과 같은 일부 사용자 관리 작업이 이루어지면 사용자에게 이메일이 전송됩니다. 수신자는 이러한 이메일에 포함된 링크를 열어 사용자 관리 작업을 완료하거나 취소할 수 있습니다. 기본적으로 사용자 관리 이메일은 기본 작업 핸들러로 연결되며, 이 핸들러는 프로젝트의 Firebase 호스팅 도메인에 호스팅된 웹페이지입니다.

커스텀 이메일 작업 핸들러를 만들고 호스팅하여 커스텀 처리를 수행하고 이메일 작업 핸들러를 웹사이트와 통합할 수도 있습니다.

다음 사용자 관리 작업에서는 사용자가 이메일 작업 핸들러를 사용하여 작업을 완료해야 합니다.

  • 비밀번호 재설정
  • 이메일 주소 변경 취소—사용자가 계정의 기본 이메일 주소를 변경하면 Firebase는 사용자가 변경을 취소할 수 있도록 이전 주소로 이메일을 보냅니다.
  • 이메일 주소 확인

Firebase 프로젝트의 이메일 작업 핸들러를 맞춤설정하려면 Firebase 자바스크립트 SDK를 사용하여 요청의 유효성을 확인하고 요청을 완료하는 웹페이지를 만들어 호스팅해야 합니다. 그런 다음 Firebase 프로젝트의 이메일 템플릿을 맞춤설정하여 커스텀 작업 핸들러로 링크해야 합니다.

이메일 작업 핸들러 페이지 만들기

  1. Firebase는 사용자 관리 이메일을 생성할 때 작업 핸들러 URL에 몇 가지 쿼리 매개변수를 추가합니다. 예를 들면 다음과 같습니다.

    https://example.com/usermgmt?mode=resetPassword&oobCode=ABC123&apiKey=AIzaSy...&lang=fr

    이러한 매개변수는 사용자가 완료하는 사용자 관리 작업을 지정합니다. 이메일 작업 핸들러 페이지는 다음 쿼리 매개변수를 처리해야 합니다.

    매개변수
    모드

    완료할 사용자 관리 작업입니다. 다음 값 중 하나일 수 있습니다.

    • resetPassword
    • recoverEmail
    • verifyEmail
    oobCode 요청을 식별하고 확인하는 데 사용되는 일회용 코드입니다.
    apiKey Firebase 프로젝트의 API 키로서 편의를 위해 제공됩니다.
    continueUrl URL을 통해 상태를 앱으로 다시 전달할 수 있는 선택적 URL로, 비밀번호 재설정 및 이메일 확인 모드에 사용됩니다 비밀번호 재설정 이메일 또는 확인 메일을 보낼 때 ActionCodeSettings 객체를 사용하려면 연결 URL로 지정해야 합니다. 이렇게 하면 사용자가 이메일 작업을 마친 지점에서 계속 진행할 수 있게 됩니다.
    lang

    선택사항인 BCP47 언어 태그이며 사용자의 언어를 나타냅니다(예: fr). 이 값을 사용해 현지화된 이메일 작업 핸들러 페이지를 사용자에게 제공할 수 있습니다.

    현지화는 Firebase Console을 통하거나 이메일 작업을 트리거하기 전에 해당 클라이언트 API를 호출하여 동적으로 설정할 수 있습니다. 예를 들어 자바스크립트 firebase.auth().languageCode = 'fr';을 사용하면 됩니다.

    사용자 경험을 일관성 있게 제공하려면 이메일 작업 핸들러 현지화가 이메일 템플릿의 현지화와 일치하는지 확인하세요.

    다음 예는 브라우저 기반 핸들러에서 쿼리 매개변수를 처리하는 방법을 보여줍니다. 유사한 로직을 사용하여 Node.js 애플리케이션으로 핸들러를 구현할 수도 있습니다.

    Web

    import { initializeApp } from "firebase/app";
    import { getAuth } from "firebase/auth";
    
    document.addEventListener('DOMContentLoaded', () => {
      // TODO: Implement getParameterByName()
    
      // Get the action to complete.
      const mode = getParameterByName('mode');
      // Get the one-time code from the query parameter.
      const actionCode = getParameterByName('oobCode');
      // (Optional) Get the continue URL from the query parameter if available.
      const continueUrl = getParameterByName('continueUrl');
      // (Optional) Get the language code if available.
      const lang = getParameterByName('lang') || 'en';
    
      // Configure the Firebase SDK.
      // This is the minimum configuration required for the API to be used.
      const config = {
        'apiKey': "YOUR_API_KEY" // Copy this key from the web initialization
                                 // snippet found in the Firebase console.
      };
      const app = initializeApp(config);
      const auth = getAuth(app);
    
      // Handle the user management action.
      switch (mode) {
        case 'resetPassword':
          // Display reset password handler and UI.
          handleResetPassword(auth, actionCode, continueUrl, lang);
          break;
        case 'recoverEmail':
          // Display email recovery handler and UI.
          handleRecoverEmail(auth, actionCode, lang);
          break;
        case 'verifyEmail':
          // Display email verification handler and UI.
          handleVerifyEmail(auth, actionCode, continueUrl, lang);
          break;
        default:
          // Error: invalid mode.
      }
    }, false);

    Web

    document.addEventListener('DOMContentLoaded', () => {
      // TODO: Implement getParameterByName()
    
      // Get the action to complete.
      var mode = getParameterByName('mode');
      // Get the one-time code from the query parameter.
      var actionCode = getParameterByName('oobCode');
      // (Optional) Get the continue URL from the query parameter if available.
      var continueUrl = getParameterByName('continueUrl');
      // (Optional) Get the language code if available.
      var lang = getParameterByName('lang') || 'en';
    
      // Configure the Firebase SDK.
      // This is the minimum configuration required for the API to be used.
      var config = {
        'apiKey': "YOU_API_KEY" // Copy this key from the web initialization
                                // snippet found in the Firebase console.
      };
      var app = firebase.initializeApp(config);
      var auth = app.auth();
    
      // Handle the user management action.
      switch (mode) {
        case 'resetPassword':
          // Display reset password handler and UI.
          handleResetPassword(auth, actionCode, continueUrl, lang);
          break;
        case 'recoverEmail':
          // Display email recovery handler and UI.
          handleRecoverEmail(auth, actionCode, lang);
          break;
        case 'verifyEmail':
          // Display email verification handler and UI.
          handleVerifyEmail(auth, actionCode, continueUrl, lang);
          break;
        default:
          // Error: invalid mode.
      }
    }, false);
  2. 비밀번호 재설정 요청을 처리하려면 우선 verifyPasswordResetCode로 작업 코드를 확인한 후 사용자에게 새 비밀번호를 입력받아 confirmPasswordReset에 전달합니다. 예를 들면 다음과 같습니다.

    Web

    import { verifyPasswordResetCode, confirmPasswordReset } from "firebase/auth";
    
    function handleResetPassword(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
    
      // Verify the password reset code is valid.
      verifyPasswordResetCode(auth, actionCode).then((email) => {
        const accountEmail = email;
    
        // TODO: Show the reset screen with the user's email and ask the user for
        // the new password.
        const newPassword = "...";
    
        // Save the new password.
        confirmPasswordReset(auth, actionCode, newPassword).then((resp) => {
          // Password reset has been confirmed and new password updated.
    
          // TODO: Display a link back to the app, or sign-in the user directly
          // if the page belongs to the same domain as the app:
          // auth.signInWithEmailAndPassword(accountEmail, newPassword);
    
          // TODO: If a continue URL is available, display a button which on
          // click redirects the user back to the app via continueUrl with
          // additional state determined from that URL's parameters.
        }).catch((error) => {
          // Error occurred during confirmation. The code might have expired or the
          // password is too weak.
        });
      }).catch((error) => {
        // Invalid or expired action code. Ask user to try to reset the password
        // again.
      });
    }

    Web

    function handleResetPassword(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
    
      // Verify the password reset code is valid.
      auth.verifyPasswordResetCode(actionCode).then((email) => {
        var accountEmail = email;
    
        // TODO: Show the reset screen with the user's email and ask the user for
        // the new password.
        var newPassword = "...";
    
        // Save the new password.
        auth.confirmPasswordReset(actionCode, newPassword).then((resp) => {
          // Password reset has been confirmed and new password updated.
    
          // TODO: Display a link back to the app, or sign-in the user directly
          // if the page belongs to the same domain as the app:
          // auth.signInWithEmailAndPassword(accountEmail, newPassword);
    
          // TODO: If a continue URL is available, display a button which on
          // click redirects the user back to the app via continueUrl with
          // additional state determined from that URL's parameters.
        }).catch((error) => {
          // Error occurred during confirmation. The code might have expired or the
          // password is too weak.
        });
      }).catch((error) => {
        // Invalid or expired action code. Ask user to try to reset the password
        // again.
      });
    }
  3. 이메일 주소 변경 취소를 처리하려면 우선 checkActionCode로 작업 코드를 확인한 후 applyActionCode로 사용자 이메일 주소를 복원합니다. 예를 들면 다음과 같습니다.

    Web

    import { checkActionCode, applyActionCode, sendPasswordResetEmail } from "firebase/auth";
    
    function handleRecoverEmail(auth, actionCode, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      let restoredEmail = null;
      // Confirm the action code is valid.
      checkActionCode(auth, actionCode).then((info) => {
        // Get the restored email address.
        restoredEmail = info['data']['email'];
    
        // Revert to the old email.
        return applyActionCode(auth, actionCode);
      }).then(() => {
        // Account email reverted to restoredEmail
    
        // TODO: Display a confirmation message to the user.
    
        // You might also want to give the user the option to reset their password
        // in case the account was compromised:
        sendPasswordResetEmail(auth, restoredEmail).then(() => {
          // Password reset confirmation sent. Ask user to check their email.
        }).catch((error) => {
          // Error encountered while sending password reset code.
        });
      }).catch((error) => {
        // Invalid code.
      });
    }

    Web

    function handleRecoverEmail(auth, actionCode, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      var restoredEmail = null;
      // Confirm the action code is valid.
      auth.checkActionCode(actionCode).then((info) => {
        // Get the restored email address.
        restoredEmail = info['data']['email'];
    
        // Revert to the old email.
        return auth.applyActionCode(actionCode);
      }).then(() => {
        // Account email reverted to restoredEmail
    
        // TODO: Display a confirmation message to the user.
    
        // You might also want to give the user the option to reset their password
        // in case the account was compromised:
        auth.sendPasswordResetEmail(restoredEmail).then(() => {
          // Password reset confirmation sent. Ask user to check their email.
        }).catch((error) => {
          // Error encountered while sending password reset code.
        });
      }).catch((error) => {
        // Invalid code.
      });
    }
  4. 이메일 주소 인증을 처리하려면 applyActionCode를 호출합니다. 예를 들면 다음과 같습니다.

    Web

    function handleVerifyEmail(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      // Try to apply the email verification code.
      applyActionCode(auth, actionCode).then((resp) => {
        // Email address has been verified.
    
        // TODO: Display a confirmation message to the user.
        // You could also provide the user with a link back to the app.
    
        // TODO: If a continue URL is available, display a button which on
        // click redirects the user back to the app via continueUrl with
        // additional state determined from that URL's parameters.
      }).catch((error) => {
        // Code is invalid or expired. Ask the user to verify their email address
        // again.
      });
    }

    Web

    function handleVerifyEmail(auth, actionCode, continueUrl, lang) {
      // Localize the UI to the selected language as determined by the lang
      // parameter.
      // Try to apply the email verification code.
      auth.applyActionCode(actionCode).then((resp) => {
        // Email address has been verified.
    
        // TODO: Display a confirmation message to the user.
        // You could also provide the user with a link back to the app.
    
        // TODO: If a continue URL is available, display a button which on
        // click redirects the user back to the app via continueUrl with
        // additional state determined from that URL's parameters.
      }).catch((error) => {
        // Code is invalid or expired. Ask the user to verify their email address
        // again.
      });
    }
  5. 예를 들어 Firebase Hosting을 사용하는 등 페이지를 임의의 위치에 호스팅합니다.

다음으로 Firebase 프로젝트를 구성하여 사용자 관리 이메일에서 커스텀 이메일 작업 핸들러로 링크해야 합니다.

커스텀 이메일 작업 핸들러를 사용하도록 Firebase 프로젝트를 구성하는 방법은 다음과 같습니다.

  1. Firebase 콘솔에서 프로젝트를 엽니다.
  2. 인증 섹션에서 이메일 템플릿 페이지로 이동합니다.
  3. 이메일 유형 항목 중 하나에서 연필 아이콘을 클릭하여 이메일 템플릿을 수정합니다.
  4. 작업 URL 직접 입력을 클릭하고 커스텀 이메일 작업 핸들러의 URL을 지정합니다.

URL을 저장하면 모든 Firebase 프로젝트의 이메일 템플릿에 이 URL이 사용됩니다.