Hành Trình Tích Hợp Decap CMS với Astro Starlight trên Vercel: Lỗi OAuth và Cách Xử Lý
Hành Trình Tích Hợp Decap CMS với Astro Starlight trên Vercel
Section titled “Hành Trình Tích Hợp Decap CMS với Astro Starlight trên Vercel”Trong quá trình xây dựng hệ thống tài liệu cá nhân bằng Astro Starlight và muốn tích hợp Decap CMS để quản lý nội dung dễ dàng hơn, mình và trợ lý AI đã gặp phải một loạt vấn đề khá “khoai” liên quan đến luồng xác thực (OAuth flow) của GitHub.
Bài viết này tổng hợp lại toàn bộ quá trình bắt bệnh, giải quyết vấn đề và những bài học rút ra, hy vọng sẽ giúp những anh em đi sau tiết kiệm được vài giờ đồng hồ mò mẫm.
1. Bối cảnh dự án
Section titled “1. Bối cảnh dự án”- Framework Frontend: Astro (với template Starlight chuyên làm Docs).
- Backend/Hosting: Vercel.
- Headless CMS: Decap CMS (trước đây là Netlify CMS).
- Mục tiêu: Cho phép truy cập
/admin, đăng nhập bằng tài khoản GitHub, và ghi trực tiếp nội dung (Markdown) xuống GitHub Repositories.
2. Vấn đề 1: Setup Backend Github và Lỗi “Bấm Login lại tải file về”
Section titled “2. Vấn đề 1: Setup Backend Github và Lỗi “Bấm Login lại tải file về””Theo tài liệu chính thức của Decap CMS, khi không host trên Netlify (mà dùng nền tảng khác như Vercel), chúng ta không thể dùng cơ chế Identity mặc định của Netlify được.
Cách tiếp cận ban đầu
Section titled “Cách tiếp cận ban đầu”Chúng ta quyết định tự viết một OAuth Proxy đơn giản ngay trong thư mục API của Astro (cụ thể là src/pages/api/oauth/auth.ts và callback.ts) sử dụng package simple-oauth2.
Cấu hình trong public/admin/config.yml được trỏ tới file API này:
backend: name: github repo: tendangnhap/ten-repo branch: main auth_endpoint: api/oauth/authTriệu chứng lỗi
Section titled “Triệu chứng lỗi”Khi vào trang /admin, giao diện Decap CMS hiện lên bình thường. Nhưng khi click nút “Login with GitHub”, thay vì chuyển hướng sang trang xác thực của GitHub thì trình duyệt lại… tự động tải một tệp không có đuôi mở rộng về máy.
Nguyên nhân và Giải pháp
Section titled “Nguyên nhân và Giải pháp”Sau một hồi “điều tra”, nguyên nhân cốt lõi lộ diện: Dự án Astro Starlight mặc định chạy ở chế độ Static (SSG - Static Site Generation).
- Nghĩa là mọi thứ khi build ra chỉ là các file HTML, CSS, JS tĩnh.
- Thư mục
src/pages/api/chứa mã nguồn TypeScript/JavaScript backend không hề được thực thi. Vercel tưởng đó là các file resource bình thường nên trả thẳng nội dung file cho trình duyệt tải về.
Giải pháp: Chúng ta phải kích hoạt Server-Side Rendering (SSR) hoặc Hybrid mode cho dự án Astro để các API Endpoint có thể hoạt động được như một server Node.js thực thụ.
Vào file astro.config.mjs:
import vercel from '@astrojs/vercel';
export default defineConfig({ // Chuyển sang chế độ chạy trên server output: 'server', // Sử dụng Vercel adapter (cần chạy npm i @astrojs/vercel trước) adapter: vercel(), server: { port: 4321 }, // ...cấu hình khác});Sau khi sửa và Push lên Vercel, API đã sống lại và thực hiện redirect thành công! Nút đăng nhập đã đẩy ta qua trang của GitHub.
3. Vấn đề 2: Lỗi “404 This is not the web page you are looking for” từ GitHub
Section titled “3. Vấn đề 2: Lỗi “404 This is not the web page you are looking for” từ GitHub”Triệu chứng lỗi
Section titled “Triệu chứng lỗi”API Proxy đã chạy, chuyển hướng người dùng sang https://github.com/login/oauth/authorize?.... Tuy nhiên, thay vì hiện ra bảng hỏi quyền truy cập, GitHub lại đập vào mặt thông báo lỗi 404 quen thuộc của họ (hình con kỳ lân hoặc trang báo lỗi gấu Jedi).
Nguyên nhân
Section titled “Nguyên nhân”Rất nhiều người lầm tưởng lỗi 404 là do đường truyền hay repo không tồn tại. Nhưng trong trường hợp của GitHub OAuth, lỗi 404 khi gọi /authorize CHỈ CÓ MỘT NGUYÊN NHÂN DUY NHẤT: Tham số client_id bị sai, bị thiếu hoặc không tồn tại.
Khi kiểm tra lại hàm chuyển hướng trong file auth.js của Proxy:
const clientId = process.env.GITHUB_CLIENT_ID;Hoá ra: Mặc dù chúng ta viết API lấy biến môi trường, nhưng chúng ta lại chưa cấu hình các biến Environment Variables này trên Vercel Dashboard. Biến clientId bị undefined, dẫn đến URL gửi cho GitHub bị rỗng ID, và GitHub trả về 404.
Giải pháp
Section titled “Giải pháp”- Viết thêm logic “phòng ngự” trong API Proxy để chặn lỗi sớm:
if (!clientId || !clientSecret) { return new Response("Lỗi Cấu Hình: Thiếu GITHUB_CLIENT_ID", { status: 500 });}- Thêm đầy đủ 3 biến môi trường vào Vercel (Tab Settings > Environment Variables):
GITHUB_CLIENT_ID: (Lấy từ OAuth App trên GitHub)GITHUB_CLIENT_SECRET: (Như trên)OAUTH_CALLBACK_URL:https://your-domain.vercel.app/api/oauth/callback
- Bài học xương máu: Mỗi lần cập nhật biến môi trường trên Vercel, CẦN PHẢI VÀO TAB DEPLOYMENT ĐỂ REDEPLOY LẠI BẢN BUILD MỚI NHẤT thì app mới nhận cấu hình mới.
4. Vấn đề 3: Lỗi cuối cùng - “Redirect URI Mismatch”
Section titled “4. Vấn đề 3: Lỗi cuối cùng - “Redirect URI Mismatch””Triệu chứng lỗi
Section titled “Triệu chứng lỗi”Mọi thứ tưởng đã ngon lành: Client ID đúng, Github nhận ra ứng dụng. Nhưng màn hình xác thực của GitHub lại hiện cảnh báo đỏ lòm: “The redirect_uri is not associated with this application.”
Nguyên nhân và Giải pháp
Section titled “Nguyên nhân và Giải pháp”Đây là lớp bảo mật cuối cùng của OAuth. GitHub từ chối trả mã xác thực (code) về cho trang web của bạn vì đường link trả về (Callback URL) mà trang web yêu cầu gửi tới không giống với đường link bạn khai báo lúc tạo App bên GitHub.
Trang web đang yêu cầu trả về: https://my-private-docs.vercel.app/api/oauth/callback
Trong khi cài đặt Github OAuth App lại để trắng, hoặc để là http://localhost:3000.
Giải pháp chốt hạ:
- Vào GitHub > Settings > Developer Settings > OAuth Apps > [App của bạn]
- Tại trường “Authorization callback URL”, điền CHÍNH XÁC URL mà web bạn đang chạy. Phải khớp 100% bao gồm cả
https://. - Đảm bảo biến
OAUTH_CALLBACK_URLtrên Vercel cũng khớp chữ từng chữ một với link này.
5. Tổng kết & Lời Khuyên
Section titled “5. Tổng kết & Lời Khuyên”Setup Decap CMS cho dự án Astro + Vercel không hề khó, nhưng rất dễ “sập hố” vì thiếu kinh nghiệm nối ghép các hệ sinh thái lại với nhau. Cấu trúc chuẩn cuối cùng để mọi thứ chạy mượt mà là:
- Astro phải ở chế độ SSR (Server) hoặc Hybrid. (Cài
@astrojs/vercel). - Setup OAuth Proxy nội bộ (
api/oauth/authvàapi/oauth/callback) để giấuClient Secrettrên server. - Cấu hình Vercel Environment Variables đầy đủ (
CLIENT_ID,CLIENT_SECRET,CALLBACK_URL) và nhớ Redeploy. - Đồng bộ Callback URL giữa code Vercel và cài đặt trên GitHub.
Nếu không muốn đau đầu tự quản lý OAuth Proxy, có một “Hướng đi khác” (Alternative Route) cực kỳ đáng giá: Chuyển sang dùng Keystatic CMS. Keystatic được thiết kế native cho NextJS/Astro, hoạt động hoàn hảo 100% ở chế độ Static (không phải tốn tiền chạy server function) và tự động lo liệu toàn bộ flow của GitHub OAuth Auth!
Với những ai đang build Astro Starlight, Keystatic thực sự là một lựa chọn “cùng rơ” hơn so với Decap CMS ở thời điểm hiện tại.
Chúc anh em code không dính bug!
� �#�#� �6�.� �P�h�� �L��c�:� �T�h���m� �C��n�g� �T���c� �V�i���n� �(�S�h�a�r�e� �Q�u�y��n� �n�g� �N�h��p� �C�M�S�)� � �B��n� �n�g�u�y���n� �t�h��y� �c��a� �D�e�c�a�p� �C�M�S� �t�h���n�g� �q�u�a� �N�e�t�l�i�f�y� �I�d�e�n�t�i�t�y� �c��� �t�h�� �h�� �t�r�� �m��i� �q�u�a� �E�m�a�i�l� �(�v��i� �h�� �t�h��n�g� �x���c� �t�h��c� �n�g���i� �d���n�g� �r�i���n�g� �b�i��t�)�.� �N�h��n�g� �v��i� �m��� �h���n�h� �G�i�t�H�u�b� �O�A�u�t�h� �t�� �p�h���t� �t�r�i��n� �n�h�� �c�h���n�g� �t�a� �a�n�g� �l���m�,� �n�g���i� �n�g�o���i� �v��n� �c��� �t�h�� �d���n�g� �C�M�S� �m��� �k�h���n�g� �l�o��n�g� �n�g�o��n�g�,� �t�h�e�o� �c���c� �b���c� �s�a�u�:� � �1�.� ���N�g�u�y���n� �t��c�:��� �B��t� �c�� �a�i� �c��� �t���i� �k�h�o��n� �G�i�t�H�u�b� �V��� ���c� �b��n� �c��p� �q�u�y��n� �G�H�I� �(�W�r�i�t�e� �A�c�c�e�s�s�)� �v���o� �R�e�p�o�s�i�t�o�r�y� �c�h��a� �m��� �n�g�u��n� �g��c� ��u� �c��� �t�h�� �n�g� �n�h��p� ���c� �v���o� �C�M�S�.� �2�.� ���C���c�h� �c��p� �q�u�y��n�:��� � � � � �-� �N�g���i� �q�u��n� �t�r�� �r�e�p�o� �c�h���n�h� �(�b��n�)� �v���o� �G�i�t�H�u�b� �-�>� �M�� �R�e�p�o� �c�h��a� �s�o�u�r�c�e� �c�o�d�e� �\�m�y�-�p�r�i�v�a�t�e�-�d�o�c�s�\�.� � � � � �-� �C�h��n� �c��t� ���S�e�t�t�i�n�g�s��� �-�>� ���C�o�l�l�a�b�o�r�a�t�o�r�s��� �-�>� �B��m� ���A�d�d� �p�e�o�p�l�e���.� � � � � �-� �N�h��p� �u�s�e�r�n�a�m�e� �h�o��c� �e�m�a�i�l� �G�i�t�H�u�b� �c��a� �n�g���i� �b��n� �m�u��n� �c�h�i�a� �s��,� �c��p� �q�u�y��n� �W�r�i�t�e�,� �v��� �b��m� �m��i�.� � � � � �-� �N�g���i� ���c� �m��i� �v���o� �E�m�a�i�l� �h�o��c� �G�i�t�H�u�b� �c�h��p� �n�h��n� �l��i� �m��i� �(�A�c�c�e�p�t� �I�n�v�i�t�a�t�i�o�n�)�.� �3�.� ���C���c�h� �n�g� �n�h��p�:��� � � � � �-� �N�g���i� ��� �t�r�u�y� �c��p� �t�r�a�n�g� �q�u��n� �t�r�� �c��a� �b��n� �(�V�D�:� �\�h�t�t�p�s�:�/�/�d�o�m�a�i�n�-�c�u�a�-�b�a�n�/�a�d�m�i�n�\�)�.� � � � � �-� �B��m� �n���t� ���L�o�g�i�n� �w�i�t�h� �G�i�t�H�u�b��� �n�h�� �b���n�h� �t�h���n�g�.� � � � � �-� �C��p� �q�u�y��n� �c�h�o� �O�A�u�t�h� �A�p�p� �l��� �x�o�n�g�.� �M��i� �b���i� �v�i��t� �h�� �n�g� �s�� ���c� �t��o� �t�h���n�h� �C�o�m�m�i�t� �d���i� �t���n� �c��a� �c�h���n�h� �h�� �t�r���n� �G�i�t�H�u�b�.� � �