Firebase 는 NoSQL 데이터베이스, 인증, 실시간 구독, 함수, 스토리지를 제공하는 앱 개발 플랫폼입니다.
Firebase hosting에 배포 에 대한 별도의 가이드를 참조하세요.
웹 앱이 구성된 Firebase 프로젝트 .
요청 시 렌더링을 위해 output: 'server'
가 활성화된 Astro 프로젝트.
Firebase 자격 증명: Astro를 Firebase에 연결하려면 두 가지 자격 증명 세트가 필요합니다.
웹 앱 자격 증명: 이 자격 증명은 앱의 클라이언트 측에서 사용됩니다. Firebase 콘솔의 Project settings > General 에서 찾을 수 있습니다. Your apps 섹션까지 아래로 스크롤하고 Web app 아이콘을 클릭합니다.
프로젝트 자격 증명: 이 자격 증명은 앱의 서버 측에서 사용됩니다. Firebase 콘솔의 Project settings > Service accounts > Firebase Admin SDK > Generate new private key 에서 생성할 수 있습니다.
Astro에 Firebase 사용자 인증 정보를 추가하려면 다음 변수를 사용하여 프로젝트 루트에 .env
파일을 만듭니다.
FIREBASE_PRIVATE_KEY_ID =YOUR_PRIVATE_KEY_ID
FIREBASE_PRIVATE_KEY =YOUR_PRIVATE_KEY
FIREBASE_PROJECT_ID =YOUR_PROJECT_ID
FIREBASE_CLIENT_EMAIL =YOUR_CLIENT_EMAIL
FIREBASE_CLIENT_ID =YOUR_CLIENT_ID
FIREBASE_AUTH_URI =YOUR_AUTH_URI
FIREBASE_TOKEN_URI =YOUR_TOKEN_URI
FIREBASE_AUTH_CERT_URL =YOUR_AUTH_CERT_URL
FIREBASE_CLIENT_CERT_URL =YOUR_CLIENT_CERT_URL
이제 이러한 환경 변수를 프로젝트에서 사용할 수 있습니다.
Firebase 환경 변수에 IntelliSense를 사용하려면 src/
디렉터리에서 env.d.ts
파일을 편집하거나 생성하고 타입을 구성하세요.
interface ImportMetaEnv {
readonly FIREBASE_PRIVATE_KEY_ID : string ;
readonly FIREBASE_PRIVATE_KEY : string ;
readonly FIREBASE_PROJECT_ID : string ;
readonly FIREBASE_CLIENT_EMAIL : string ;
readonly FIREBASE_CLIENT_ID : string ;
readonly FIREBASE_AUTH_URI : string ;
readonly FIREBASE_TOKEN_URI : string ;
readonly FIREBASE_AUTH_CERT_URL : string
readonly FIREBASE_CLIENT_CERT_URL : string ;
readonly env : ImportMetaEnv ;
이제 프로젝트에 다음과 같은 새 파일이 포함되어야 합니다.
디렉터리 src/
.env astro.config.mjs package.json
Astro를 Firebase와 연결하려면 원하는 패키지 관리자에 대해 아래 단일 명령을 사용하여 다음 패키지를 설치하세요.
firebase
- 클라이언트용 Firebase SDK
firebase-admin
- 서버용 Firebase Admin SDK
npm install firebase firebase-admin
pnpm add firebase firebase-admin
yarn add firebase firebase-admin
다음으로 src/
디렉터리에 firebase
라는 폴더를 만들고 이 폴더에 client.ts
및 server.ts
라는 두 개의 새 파일을 추가합니다.
client.ts
에 다음 코드를 추가하여 웹 앱 사용자 인증 정보와 firebase
패키지를 사용하여 클라이언트에서 Firebase를 초기화합니다.
import { initializeApp } from " firebase/app " ;
apiKey: " my-public-api-key " ,
authDomain: " my-auth-domain " ,
projectId: " my-project-id " ,
storageBucket: " my-storage-bucket " ,
messagingSenderId: " my-sender-id " ,
export const app = initializeApp (firebaseConfig);
server.ts
에서 다음 코드를 추가하여 프로젝트 자격 증명과 firebase-admin
패키지를 사용하여 서버에서 Firebase를 초기화합니다.
import type { ServiceAccount } from " firebase-admin " ;
import { initializeApp, cert, getApps } from " firebase-admin/app " ;
const activeApps = getApps ();
project_id: import. meta . env . FIREBASE_PROJECT_ID ,
private_key_id: import. meta . env . FIREBASE_PRIVATE_KEY_ID ,
private_key: import. meta . env . FIREBASE_PRIVATE_KEY ,
client_email: import. meta . env . FIREBASE_CLIENT_EMAIL ,
client_id: import. meta . env . FIREBASE_CLIENT_ID ,
auth_uri: import. meta . env . FIREBASE_AUTH_URI ,
token_uri: import. meta . env . FIREBASE_TOKEN_URI ,
auth_provider_x509_cert_url: import. meta . env . FIREBASE_AUTH_CERT_URL ,
client_x509_cert_url: import. meta . env . FIREBASE_CLIENT_CERT_URL ,
if ( import. meta . env . PROD ) {
console . info ( ' PROD env detected. Using default service account. ' )
// Firebase 함수에서 기본 구성을 사용합니다. Firebase에 의해 이미 서버에 삽입되어 있어야 합니다.
console . info ( ' Loading service account from env. ' )
credential: cert (serviceAccount as ServiceAccount )
export const app = activeApps . length === 0 ? initApp () : activeApps[ 0 ];
마지막으로 이제 프로젝트에 다음과 같은 새 파일이 포함되어야 합니다.
디렉터리 src
.env astro.config.mjs package.json
Astro 프로젝트 Firebase로 초기화 .
Firebase 콘솔의 Authentication > Sign-in 에서 이메일/비밀번호 인증이 활성화된 Firebase 프로젝트.
Astro에서 Firebase 인증을 수행하려면 다음 세 가지 Astro 서버 엔드포인트 가 필요합니다.
GET /api/auth/signin
- 사용자 로그인
GET /api/auth/signout
- 사용자 로그아웃
POST /api/auth/register
- 사용자 등록
새 디렉터리 src/pages/api/auth/
에 인증과 관련된 3개의 엔드포인트 (signin.ts
, signout.ts
, register.ts
)를 만듭니다.
signin.ts
에는 Firebase를 사용하여 사용자를 로그인하는 코드가 포함되어 있습니다.
import type { APIRoute } from " astro " ;
import { app } from " ../../../firebase/server " ;
import { getAuth } from " firebase-admin/auth " ;
export const GET : APIRoute = async ( { request , cookies , redirect } ) => {
const auth = getAuth (app) ;
const idToken = request . headers . get ( " Authorization " ) ?. split ( " Bearer " )[ 1 ] ;
await auth . verifyIdToken (idToken) ;
const fiveDays = 60 * 60 * 24 * 5 * 1000 ;
const sessionCookie = await auth . createSessionCookie (idToken , {
cookies . set ( " __session " , sessionCookie , {
return redirect ( " /dashboard " ) ;
signout.ts
에는 세션 쿠키를 삭제하여 사용자를 로그아웃시키는 코드가 포함되어 있습니다.
import type { APIRoute } from " astro " ;
export const GET : APIRoute = async ( { redirect , cookies } ) => {
cookies . delete ( " __session " , {
return redirect ( " /signin " ) ;
register.ts
에는 Firebase를 사용하여 사용자를 등록하는 코드가 포함되어 있습니다.
import type { APIRoute } from " astro " ;
import { getAuth } from " firebase-admin/auth " ;
import { app } from " ../../../firebase/server " ;
export const POST : APIRoute = async ( { request , redirect } ) => {
const auth = getAuth (app) ;
const formData = await request . formData () ;
const email = formData . get ( " email " ) ?. toString () ;
const password = formData . get ( " password " ) ?. toString () ;
const name = formData . get ( " name " ) ?. toString () ;
if ( ! email || ! password || ! name) {
return redirect ( " /signin " ) ;
인증을 위한 서버 엔드포인트를 생성한 후에는 이제 프로젝트 디렉터리에 다음과 같은 새 파일이 포함되어야 합니다.
디렉터리 src
env.d.ts디렉터리 firebase
디렉터리 pages
디렉터리 api
디렉터리 auth
signin.ts signout.ts register.ts .env astro.config.mjs package.json
Firebase 엔드포인트를 사용할 페이지를 만듭니다.
src/pages/register
- 사용자를 등록하는 양식이 포함되어 있습니다.
src/pages/signin
- 사용자 로그인을 위한 양식이 포함됩니다.
src/pages/dashboard
- 인증된 사용자만 액세스할 수 있는 대시보드가 포함됩니다.
아래의 src/pages/register.astro
예시에는 /api/auth/register
엔드포인트에 POST
요청을 보내는 양식이 포함되어 있습니다. 이 엔드포인트는 양식의 데이터를 사용하여 새 사용자를 생성한 다음 사용자를 /signin
페이지로 리디렉션합니다.
import Layout from " ../layouts/Layout.astro " ;
< Layout title = " Register " >
< p > Already have an account? < a href = " /signin " > Sign in </ a ></ p >
< form action = " /api/auth/register " method = " post " >
< label for = " name " > Name </ label >
< input type = " text " name = " name " id = " name " />
< label for = " email " for = " email " > Email </ label >
< input type = " email " name = " email " id = " email " />
< label for = " password " > Password </ label >
< input type = " password " name = " password " id = " password " />
< button type = " submit " > Login </ button >
src/pages/signin.astro
는 Firebase 서버 앱을 사용하여 사용자의 세션 쿠키를 확인합니다. 사용자가 인증되면 페이지는 사용자를 /dashboard
페이지로 리디렉션합니다.
아래 예시 페이지에는 Firebase 클라이언트 앱에서 생성된 ID 토큰을 사용하여 /api/auth/signin
엔드포인트에 POST
요청을 보내는 양식이 포함되어 있습니다.
엔드포인트는 ID 토큰을 확인하고 사용자를 위한 새 세션 쿠키를 생성합니다. 그런 다음 엔드포인트는 사용자를 /dashboard
페이지로 리디렉션합니다.
import { app } from " ../firebase/server " ;
import { getAuth } from " firebase-admin/auth " ;
import Layout from " ../layouts/Layout.astro " ;
const auth = getAuth (app);
if (Astro . cookies . has ( " __session " )) {
const sessionCookie = Astro . cookies . get ( " __session " ) . value ;
const decodedCookie = await auth . verifySessionCookie (sessionCookie);
return Astro . redirect ( " /dashboard " );
< p > New here? < a href = " /register " > Create an account </ a ></ p >
< form action = " /api/auth/signin " method = " post " >
< label for = " email " for = " email " > Email </ label >
< input type = " email " name = " email " id = " email " />
< label for = " password " > Password </ label >
< input type = " password " name = " password " id = " password " />
< button type = " submit " > Login </ button >
signInWithEmailAndPassword,
import { app } from " ../firebase/client " ;
const auth = getAuth ( app );
// This will prevent the browser from storing session data
auth . setPersistence ( inMemoryPersistence );
const form = document . querySelector ( " form " ) as HTMLFormElement ;
form . addEventListener ( " submit " , async ( e ) => {
const formData = new FormData ( form );
const email = formData . get ( " email " ) ?. toString ();
const password = formData . get ( " password " ) ?. toString ();
if ( ! email || ! password ) {
const userCredential = await signInWithEmailAndPassword (
const idToken = await userCredential . user . getIdToken ();
const response = await fetch ( " /api/auth/signin " , {
Authorization: ` Bearer ${ idToken } ` ,
if ( response . redirected ) {
window . location . assign ( response . url );
src/pages/dashboard.astro
는 Firebase 서버 앱을 사용하여 사용자의 세션 쿠키를 확인합니다. 사용자가 인증되지 않은 경우 페이지는 사용자를 /signin
페이지로 리디렉션합니다.
아래 예시 페이지에는 사용자 이름과 로그아웃 버튼이 표시되어 있습니다. 버튼을 클릭하면 GET
요청이 /api/auth/signout
엔드포인트로 전송됩니다.
엔드포인트는 사용자의 세션 쿠키를 삭제하고 사용자를 /signin
페이지로 리디렉션합니다.
import { app } from " ../firebase/server " ;
import { getAuth } from " firebase-admin/auth " ;
import Layout from " ../layouts/Layout.astro " ;
const auth = getAuth (app);
if ( ! Astro . cookies . has ( " __session " )) {
return Astro . redirect ( " /signin " );
const sessionCookie = Astro . cookies . get ( " __session " ) . value ;
const decodedCookie = await auth . verifySessionCookie (sessionCookie);
const user = await auth . getUser (decodedCookie . uid );
return Astro . redirect ( " /signin " );
< Layout title = " dashboard " >
< h1 > Welcome { user . displayName } </ h1 >
< p > We are happy to see you here </ p >
< form action = " /api/auth/signout " >
< button type = " submit " > Sign out </ button >
앱에 OAuth 공급자를 추가하려면 Firebase 콘솔에서 이를 활성화해야 합니다.
Firebase 콘솔에서 Authentication 섹션으로 이동하여 Sign-in method 탭을 클릭하세요. 그런 다음 Add a new provider 버튼을 클릭하여 사용하려는 제공업체를 활성화하세요.
아래 예시에서는 Google 공급자를 사용합니다.
다음을 추가하려면 signin.astro
페이지를 편집하세요.
기존 양식 아래에 Google로 로그인하는 버튼
기존 <script>
의 로그인 프로세스를 처리하기 위한 버튼의 이벤트 리스너
import { app } from " ../firebase/server " ;
import { getAuth } from " firebase-admin/auth " ;
import Layout from " ../layouts/Layout.astro " ;
const auth = getAuth (app);
if (Astro . cookies . has ( " __session " )) {
const sessionCookie = Astro . cookies . get ( " __session " ) . value ;
const decodedCookie = await auth . verifySessionCookie (sessionCookie);
return Astro . redirect ( " /dashboard " );
< p > New here? < a href = " /register " > Create an account </ a ></ p >
< form action = " /api/auth/signin " method = " post " >
< label for = " email " for = " email " > Email </ label >
< input type = " email " name = " email " id = " email " />
< label for = " password " > Password </ label >
< input type = " password " name = " password " id = " password " />
< button type = " submit " > Login </ button >
< button id = " google " > Sign in with Google </ button >
signInWithEmailAndPassword,
import { app } from " ../firebase/client " ;
const auth = getAuth ( app );
auth . setPersistence ( inMemoryPersistence );
const form = document . querySelector ( " form " ) as HTMLFormElement ;
form . addEventListener ( " submit " , async ( e ) => {
const formData = new FormData ( form );
const email = formData . get ( " email " ) ?. toString ();
const password = formData . get ( " password " ) ?. toString ();
if ( ! email || ! password ) {
const userCredential = await signInWithEmailAndPassword (
const idToken = await userCredential . user . getIdToken ();
const response = await fetch ( " /api/auth/signin " , {
Authorization: ` Bearer ${ idToken } ` ,
if ( response . redirected ) {
window . location . assign ( response . url );
const googleSignin = document . querySelector ( " #google " ) as HTMLButtonElement ;
googleSignin . addEventListener ( " click " , async () => {
const provider = new GoogleAuthProvider ();
const userCredential = await signInWithPopup ( auth , provider );
const idToken = await userCredential . user . getIdToken ();
const res = await fetch ( " /api/auth/signin " , {
Authorization: ` Bearer ${ idToken } ` ,
window . location . assign ( res . url );
Google 로그인 버튼을 클릭하면 Google로 로그인할 수 있는 팝업 창이 열립니다. 사용자가 로그인하면 OAuth 공급자가 생성한 ID 토큰을 사용하여 /api/auth/signin
엔드포인트에 POST
요청을 보냅니다.
엔드포인트는 ID 토큰을 확인하고 사용자를 위한 새 세션 쿠키를 생성합니다. 그런 다음 엔드포인트는 사용자를 /dashboard
페이지로 리디렉션합니다.
이 레시피에서 Firestore 컬렉션은 friends 라고 하며 다음 필드가 있는 문서를 포함합니다.
id
: Firestore에서 자동 생성됨
name
: 문자열 필드
age
: 숫자 필드
isBestFriend
: 부울 필드
새 디렉터리 src/pages/api/friends/
에 index.ts
및 [id].ts
라는 두 개의 새 파일을 만듭니다. 그러면 다음과 같은 방법으로 Firestore 데이터베이스와 상호작용하는 두 개의 서버 엔드포인트가 생성됩니다.
POST /api/friends
: friends 컬렉션에 새 문서 생성
POST /api/friends/:id
: friends 컬렉션의 문서를 업데이트
DELETE /api/friends/:id
: friends 컬렉션에 있는 문서를 삭제
index.ts
에는 friends 컬렉션에 새 문서를 생성하는 코드가 포함됩니다.
import type { APIRoute } from " astro " ;
import { app } from " ../../../firebase/server " ;
import { getFirestore } from " firebase-admin/firestore " ;
export const POST : APIRoute = async ( { request , redirect } ) => {
const formData = await request . formData () ;
const name = formData . get ( " name " ) ?. toString () ;
const age = formData . get ( " age " ) ?. toString () ;
const isBestFriend = formData . get ( " isBestFriend " ) === " on " ;
return new Response ( " Missing required fields " , {
const db = getFirestore (app) ;
const friendsRef = db . collection ( " friends " ) ;
return new Response ( " Something went wrong " , {
return redirect ( " /dashboard " ) ;
[id].ts
에는 friends 컬렉션의 문서를 업데이트하고 삭제하는 코드가 포함되어 있습니다.
import type { APIRoute } from " astro " ;
import { app } from " ../../../firebase/server " ;
import { getFirestore } from " firebase-admin/firestore " ;
const db = getFirestore (app);
const friendsRef = db . collection ( " friends " );
export const POST : APIRoute = async ( { params , redirect , request } ) => {
const formData = await request . formData () ;
const name = formData . get ( " name " ) ?. toString () ;
const age = formData . get ( " age " ) ?. toString () ;
const isBestFriend = formData . get ( " isBestFriend " ) === " on " ;
return new Response ( " Missing required fields " , {
return new Response ( " Cannot find friend " , {
await friendsRef . doc (params . id ) . update ( {
return new Response ( " Something went wrong " , {
return redirect ( " /dashboard " ) ;
export const DELETE : APIRoute = async ( { params , redirect } ) => {
return new Response ( " Cannot find friend " , {
await friendsRef . doc (params . id ) . delete () ;
return new Response ( " Something went wrong " , {
return redirect ( " /dashboard " ) ;
Firestore용 서버 엔드포인트를 생성한 후에는 이제 프로젝트 디렉터리에 다음과 같은 새 파일이 포함되어야 합니다.
디렉터리 src
env.d.ts디렉터리 firebase
디렉터리 pages
.env astro.config.mjs package.json
Firestore 엔드포인트를 사용할 페이지를 만듭니다.
src/pages/add.astro
- 새 friend를 추가하는 양식이 포함되어 있습니다.
src/pages/edit/[id].astro
- friend를 편집하는 양식과 friend를 삭제하는 버튼이 포함되어 있습니다.
src/pages/friend/[id].astro
- friend의 세부 정보가 포함됩니다.
src/pages/dashboard.astro
- friends 목록이 표시됩니다.
아래의 src/pages/add.astro
예시에는 /api/friends
엔드포인트에 POST
요청을 보내는 양식이 포함되어 있습니다. 이 엔드포인트는 양식의 데이터를 사용하여 새 friend를 만든 다음 사용자를 /dashboard
페이지로 리디렉션합니다.
import Layout from " ../layouts/Layout.astro " ;
< Layout title = " Add a new friend " >
< h1 > Add a new friend </ h1 >
< form method = " post " action = " /api/friends " >
< label for = " name " > Name </ label >
< input type = " text " id = " name " name = " name " />
< label for = " age " > Age </ label >
< input type = " number " id = " age " name = " age " />
< label for = " isBestFriend " > Is best friend? </ label >
< input type = " checkbox " id = " isBestFriend " name = " isBestFriend " />
< button type = " submit " > Add friend </ button >
src/pages/edit/[id].astro
에는 friend 데이터를 편집하는 양식과 friend를 삭제하는 버튼이 포함되어 있습니다. 제출 시 이 페이지는 friend 데이터를 업데이트하기 위해 /api/friends/:id
엔드포인트에 POST
요청을 보냅니다.
사용자가 삭제 버튼을 클릭하면 이 페이지는 friend를 삭제하기 위해 /api/friends/:id
엔드포인트에 DELETE
요청을 보냅니다.
import Layout from " ../../layouts/Layout.astro " ;
import { app } from " ../../firebase/server " ;
import { getFirestore } from " firebase-admin/firestore " ;
const { id } = Astro . params ;
return Astro . redirect ( " /404 " );
const db = getFirestore (app);
const friendsRef = db . collection ( " friends " );
const friendSnapshot = await friendsRef . doc (id) . get ();
if ( ! friendSnapshot . exists ) {
return Astro . redirect ( " /404 " );
const friend = friendSnapshot . data () as Friend ;
< Layout title = " Edit {friend.name} " >
< h1 > Edit { friend . name } </ h1 >
< p > Here you can edit or delete your friend's data. </ p >
< form method = " post " action = { ` /api/friends/ ${ id } ` } >
< label for = " name " > Name </ label >
< input type = " text " id = " name " name = " name " value = { friend . name } />
< label for = " age " > Age </ label >
< input type = " number " id = " age " name = " age " value = { friend . age } />
< label for = " isBestFriend " > Is best friend? </ label >
checked = { friend . isBestFriend }
< button type = " submit " > Edit friend </ button >
< button type = " button " id = " delete-document " > Delete </ button >
const deleteButton = document . getElementById (
const url = document . querySelector ( " form " ) ?. getAttribute ( " action " ) as string ;
deleteButton . addEventListener ( " click " , async () => {
const response = await fetch ( url , {
if ( response . redirected ) {
window . location . assign ( response . url );
src/pages/friend/[id].astro
는 friend의 세부정보를 표시합니다.
import Layout from " ../../layouts/Layout.astro " ;
import { app } from " ../../firebase/server " ;
import { getFirestore } from " firebase-admin/firestore " ;
const { id } = Astro . params ;
return Astro . redirect ( " /404 " );
const db = getFirestore (app);
const friendsRef = db . collection ( " friends " );
const friendSnapshot = await friendsRef . doc (id) . get ();
if ( ! friendSnapshot . exists ) {
return Astro . redirect ( " /404 " );
const friend = friendSnapshot . data () as Friend ;
< Layout title = { friend . name } >
< p > Is best friend: { friend . isBestFriend ? " Yes " : " No " } </ p >
마지막으로 src/pages/dashboard.astro
는 friends 목록을 표시합니다. 각 friend에게는 세부 정보 페이지에 대한 링크와 사용자를 편집 페이지로 리디렉션하는 편집 버튼이 있습니다.
import { app } from " ../firebase/server " ;
import { getFirestore } from " firebase-admin/firestore " ;
import Layout from " ../layouts/Layout.astro " ;
const db = getFirestore (app);
const friendsRef = db . collection ( " friends " );
const friendsSnapshot = await friendsRef . get ();
const friends = friendsSnapshot . docs . map ( ( doc ) => ( {
< Layout title = " My friends " >
friends . map ( ( friend ) => (
< a href = { ` /friend/ ${ friend . id } ` } > { friend . name } </ a >
< span > ( { friend . age } ) </ span >
< strong > { friend . isBestFriend ? " Bestie " : " Friend " } </ strong >
< a href = { ` /edit/ ${ friend . id } ` } > Edit </ a >
모든 페이지를 생성한 후에는 다음과 같은 파일 구조를 갖게 됩니다.
디렉터리 src
env.d.ts디렉터리 firebase
디렉터리 pages
dashboard.astro add.astro디렉터리 edit
디렉터리 friend
디렉터리 api
.env astro.config.mjs package.json
더 많은 백엔드 서비스 안내서
Recipes