Tan Phat Media

OAuth PKCE Generator

Sinh code_verifier và code_challenge theo RFC 7636, dựng sẵn URL authorize và đoạn mã đổi token

Toàn bộ giá trị sinh ngẫu nhiên ngay trong trình duyệt bằng Web Crypto API. Không có request nào rời khỏi máy bạn, không lưu vào localStorage, không ghi log. Đóng tab là mất.

Cặp verifier và challenge
96 ký tự

Khoảng hợp lệ theo RFC 7636 là 43 đến 128. Ở độ dài này chuỗi mang khoảng 580 bit entropy.

...

Giữ kín ở phía client, chỉ gửi kèm ở bước đổi token.

...

BASE64URL-ENCODE(SHA256(ASCII(code_verifier))), luôn dài 43 ký tự.

...
...
Kiểm tra hợp lệ

Độ dài code_verifier nằm trong 43 đến 128

Đang là 0 ký tự

code_verifier chỉ chứa ký tự unreserved [A-Za-z0-9-._~]

Có ký tự nằm ngoài tập cho phép

code_challenge không chứa dấu cộng, gạch chéo hay bằng

Chuỗi đang là base64 thường chứ không phải base64url

Độ dài code_challenge đúng 43 ký tự

Đang là 0 ký tự

Tham số ứng dụng

Google hỗ trợ PKCE cho client kiểu Web, Android, iOS và Desktop. Client ID lấy trong Google Cloud Console, mục Credentials.

Các nút này chỉ điền endpoint mẫu. Không có client_id thật nào ở đây, bạn phải tự thay bằng của mình.

Ngăn cách bằng dấu cách. Có openid thì URL sẽ kèm thêm nonce cho luồng OpenID Connect.

URL authorize hoàn chỉnh
...

Mọi giá trị đã được mã hóa phần trăm đúng chuẩn. Trước khi chuyển hướng người dùng sang URL này, hãy lưu code_verifier và state vào sessionStorage để bước callback đọc lại được.

Đoạn mã đổi authorization code lấy token
// Chạy ở bước callback, sau khi nhà cung cấp trả ?code= về redirect_uri.
// KHÔNG bao giờ đặt client_secret trong mã chạy ở trình duyệt.
const code = new URLSearchParams(window.location.search).get("code");
const codeVerifier = sessionStorage.getItem("pkce_code_verifier");

const res = await fetch("https://oauth2.googleapis.com/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    code: code ?? "",
    redirect_uri: "https://example.com/callback",
    client_id: "your-client-id",
    code_verifier: codeVerifier ?? "",
  }),
});

if (!res.ok) throw new Error(await res.text()); // invalid_grant hay rơi vào đây
const tokens = await res.json();
// tokens.access_token, tokens.id_token, tokens.refresh_token
sessionStorage.removeItem("pkce_code_verifier");

Không gửi client_secret từ trình duyệt. Mã nguồn chạy ở client thì ai mở tab công cụ nhà phát triển cũng đọc được, secret nhúng vào đó coi như đã công khai. Client công khai dùng PKCE thay cho secret, còn nếu bắt buộc phải có secret thì bước đổi token phải chạy ở máy chủ của bạn.

Công cụ liên quan

Trang này lo bước trước khi có token. Khi đã cầm token trong tay thì dùng tiếp:

  • JWT Decoder — mở phần header và payload của access token hay id_token vừa nhận để xem claim bên trong.
  • JWT Generator — tự dựng một token mẫu để thử phía nhận, khi chưa đấu nối được với nhà cung cấp thật.
  • JWT Expiration Checker — soi trường exp và iat để biết token còn sống bao lâu, hữu ích khi gỡ lỗi vòng làm mới token.

Hợp tác ngay với Tấn Phát Digital

Chúng tôi không chỉ thiết kế website, mà còn giúp doanh nghiệp xây dựng thương hiệu số mạnh mẽ. Cung cấp dịch vụ thiết kế website trọn gói từ thiết kế đến tối ưu SEO. Hãy liên hệ ngay với Tấn Phát Digital để cùng tạo nên những giải pháp công nghệ đột phá, hiệu quả và bền vững cho doanh nghiệp của bạn tại Hồ Chí Minh.

OAuth PKCE Generator: sinh code_verifier và code_challenge đúng RFC 7636

Công cụ sinh cặp code_verifier và code_challenge cho luồng Authorization Code với PKCE, kèm state và nonce, dựng sẵn URL authorize đã mã hóa và đoạn mã fetch đổi token. Mọi giá trị tạo ngay trong trình duyệt bằng Web Crypto API, có khối kiểm tra hợp lệ đối chiếu từng ràng buộc của RFC 7636.

Tính năng nổi bật

  • Sinh code_verifier bằng crypto.getRandomValues, độ dài chỉnh được từ 43 đến 128 ký tự
  • Chỉ dùng tập ký tự unreserved A-Z a-z 0-9 và bốn ký tự gạch ngang, chấm, gạch dưới, dấu ngã
  • Tính code_challenge bằng crypto.subtle với SHA-256 rồi mã hóa base64url không phần đệm
  • Chuyển giữa S256 và plain, chọn plain thì hiện ngay cảnh báo về rủi ro tương ứng
  • Sinh kèm state và nonce từ cùng nguồn ngẫu nhiên, mỗi chuỗi 32 ký tự
  • Dựng URL authorize hoàn chỉnh với response_type, code_challenge, code_challenge_method và state
  • Năm nút điền nhanh endpoint mẫu cho Google, GitHub, Microsoft Entra ID, Auth0 và Keycloak
  • Đoạn mã fetch đổi authorization code lấy token, điền sẵn theo tham số bạn nhập, có nút chép

Vì sao nên sinh cặp PKCE bằng công cụ thay vì gõ tay

Cặp verifier và challenge trông đơn giản nhưng có bốn chỗ dễ sai mà máy chủ ủy quyền sẽ không nói cho bạn biết là sai ở đâu. Chỗ thứ nhất là tập ký tự: nhiều người lấy tạm một chuỗi UUID hoặc một chuỗi hex, chuỗi đó tuy hợp lệ nhưng entropy thấp hơn nhiều so với độ dài của nó gợi ý, hoặc tệ hơn là lấy chuỗi base64 thường có dấu cộng và gạch chéo, hai ký tự nằm ngoài tập unreserved. Chỗ thứ hai là mã hóa kết quả băm: base64 thường và base64url chỉ khác ba chi tiết nhưng sai một chi tiết là máy chủ trả invalid_grant. Chỗ thứ ba là nguồn ngẫu nhiên, Math.random không phải nguồn dùng cho mục đích bảo mật. Chỗ thứ tư là ánh xạ byte ngẫu nhiên sang tập 66 ký tự, làm ẩu bằng phép chia lấy dư sẽ khiến 58 ký tự đầu bảng xuất hiện nhiều hơn 8 ký tự cuối. Công cụ này xử lý cả bốn chỗ đó, và khối kiểm tra hợp lệ cho bạn thấy tận mắt từng ràng buộc đã đạt hay chưa trước khi đem giá trị đi thử.

Lợi ích khi sử dụng

  • Không phải nhớ chính xác công thức base64url và ràng buộc độ dài của RFC 7636
  • Khối kiểm tra hợp lệ bắt lỗi ngay tại chỗ thay vì để máy chủ trả invalid_grant mơ hồ
  • URL authorize đã mã hóa phần trăm đúng chuẩn, dán vào trình duyệt là chạy được ngay
  • Đoạn mã đổi token điền sẵn theo tham số bạn nhập, tiết kiệm bước sửa tay dễ nhầm
  • Mọi giá trị sinh trong trình duyệt, không gửi đi đâu nên dùng được cả với cấu hình nội bộ
  • Cảnh báo rõ ràng khi chọn plain, tránh việc lỡ để chế độ yếu chạy lên môi trường thật

Cách sinh cặp PKCE và dựng URL authorize

  1. 1Kéo thanh trượt để chọn độ dài code_verifier, mặc định 96 ký tự tương đương khoảng 580 bit entropy, cặp giá trị sinh lại ngay khi bạn thả tay.
  2. 2Giữ nguyên S256 trừ khi môi trường của bạn thật sự không tính được SHA-256, đọc khối kiểm tra hợp lệ để xác nhận challenge dài đúng 43 ký tự và sạch dấu cộng, gạch chéo, dấu bằng.
  3. 3Bấm một trong năm nút điền nhanh để nạp endpoint mẫu của nhà cung cấp, rồi thay client_id và redirect_uri bằng giá trị thật của ứng dụng bạn.
  4. 4Chép URL authorize, dán vào trình duyệt hoặc gắn vào nút đăng nhập, đồng thời lưu code_verifier và state vào sessionStorage trước khi chuyển hướng người dùng.
  5. 5Sau khi nhà cung cấp trả code về redirect_uri, chép đoạn mã đổi token và ghép vào trang callback, nhớ đối chiếu state nhận về với state đã lưu trước khi gọi token endpoint.

PKCE sinh ra để chặn kiểu tấn công nào

Trước khi có PKCE, ứng dụng di động và ứng dụng một trang chạy luồng Authorization Code theo cách sau: mở trình duyệt tới trang đăng nhập, người dùng đồng ý, nhà cung cấp chuyển hướng về redirect_uri kèm tham số code, ứng dụng lấy code đó đổi lấy token. Điểm yếu nằm ở bước chuyển hướng. Trên di động, redirect_uri thường là một custom URL scheme dạng myapp://callback, mà hệ điều hành không có cơ chế nào bảo đảm chỉ một ứng dụng được đăng ký scheme đó. Một ứng dụng độc hại cài sau có thể đăng ký trùng và nhận được authorization code thay vì ứng dụng thật. Trên ứng dụng một trang, code nằm ngay trong thanh địa chỉ nên lọt vào lịch sử duyệt web, log của proxy, hoặc header Referer gửi sang bên thứ ba. Ứng dụng loại này là client công khai, nghĩa là nó không giữ được client_secret: mã nguồn tải về máy người dùng, gỡ ra là đọc được, nên secret nhúng vào đó coi như công khai. Kẻ tấn công có code mà không cần secret là đổi được token. PKCE lấp đúng lỗ hổng này bằng sáu bước: client sinh code_verifier ngẫu nhiên, băm nó thành code_challenge, gửi challenge kèm request authorize, nhà cung cấp lưu challenge cùng với code vừa cấp, client gửi code kèm verifier gốc tới token endpoint, nhà cung cấp băm lại verifier và so với challenge đã lưu. Kẻ chặn được code không có verifier nên không đổi được gì.

S256 và plain: cách tính chính xác và những lỗi hay gặp

Với S256, code_challenge bằng BASE64URL-ENCODE(SHA256(ASCII(code_verifier))). Đọc từ trong ra ngoài: lấy chuỗi verifier, chuyển sang chuỗi byte theo bảng mã ASCII, băm chuỗi byte đó bằng SHA-256 ra đúng 32 byte, rồi mã hóa 32 byte đó bằng base64url. Base64url khác base64 thường ở ba chi tiết: ký tự thứ 62 là gạch ngang chứ không phải dấu cộng, ký tự thứ 63 là gạch dưới chứ không phải gạch chéo, và toàn bộ dấu bằng dùng để đệm bị bỏ đi. Lý do bỏ phần đệm là challenge được nhét vào query string của URL, mà dấu bằng ở đó mang nghĩa ngăn cách tên với giá trị nên phải mã hóa thêm một lớp, rườm rà và dễ sai. Kết quả cuối cùng luôn dài 43 ký tự vì 32 byte chia thành các nhóm 3 byte cho ra 44 ký tự base64 trong đó ký tự cuối là đệm. Hai lỗi phổ biến nhất: một là dùng hàm base64 có sẵn của ngôn ngữ rồi quên thay ký tự và bỏ đệm, hai là băm chuỗi ở dạng UTF-16 thay vì chuỗi byte ASCII, lỗi này hay gặp ở môi trường mà chuỗi mặc định là UTF-16 và hàm băm nhận thẳng chuỗi. Về entropy, khuyến nghị là verifier phải sinh từ ít nhất 256 bit ngẫu nhiên; với tập 66 ký tự, mỗi ký tự mang khoảng 6,04 bit nên 43 ký tự đã vượt 256 bit, còn 96 ký tự cho khoảng 580 bit. Với plain thì challenge bằng đúng verifier, không có phép băm nào, và ai đọc được request authorize là có luôn verifier.

PKCE khác JWT thế nào và khi nào dùng công cụ nào

Hai khái niệm này hay bị đặt cạnh nhau nhưng nằm ở hai tầng hoàn toàn khác. JWT là một định dạng token, tức là quy ước về cách đóng gói dữ liệu: ba phần header, payload và signature nối bằng dấu chấm, mỗi phần mã hóa base64url, phần chữ ký dùng để bên nhận xác minh token chưa bị sửa và đúng do bên phát hành ký. JWT trả lời câu hỏi token trông như thế nào và làm sao tin được nó. PKCE thì không phải định dạng gì cả, nó là một cơ chế bảo vệ đúng một bước trong luồng OAuth: bước đổi authorization code lấy token. PKCE trả lời câu hỏi làm sao bảo đảm người đem code đi đổi chính là người đã khởi tạo phiên đăng nhập. Trong một luồng OpenID Connect thực tế, hai thứ này chạy nối tiếp nhau: PKCE bảo vệ chặng lấy token, và token nhận về ở cuối chặng đó thường chính là JWT. Vì vậy sinh cặp PKCE sai thì bạn không bao giờ tới được bước có token để mà mở ra xem. Trang này lo chặng trước. Khi đã cầm token trong tay, site có ba công cụ cho chặng sau: /vi/tools/jwt-decoder để mở header và payload xem claim bên trong, /vi/tools/jwt-generator để tự dựng token mẫu thử phía nhận khi chưa đấu nối được với nhà cung cấp thật, và /vi/tools/jwt-expiration-checker để đọc trường exp và iat khi cần gỡ lỗi vòng làm mới token.

state, nonce và code_verifier: ba thứ khác nhau, thiếu cái nào hở cái đó

Ba tham số này cùng là chuỗi ngẫu nhiên sinh ở phía client nên rất dễ bị gộp làm một, nhưng mỗi thứ chặn một kiểu tấn công riêng và không thay thế được cho nhau. Tham số state chống giả mạo yêu cầu chéo trang ở bước callback. Bạn sinh state trước khi chuyển hướng, lưu nó lại, và khi nhà cung cấp gọi về redirect_uri thì đối chiếu state nhận được với state đã lưu; không khớp thì hủy phiên. Không có bước này, kẻ tấn công có thể dụ trình duyệt của nạn nhân gọi vào redirect_uri với một authorization code của tài khoản kẻ tấn công, khiến nạn nhân vô tình đăng nhập vào tài khoản đó rồi lưu dữ liệu riêng tư vào đấy. Tham số nonce thuộc về OpenID Connect, nó được nhà cung cấp nhúng thẳng vào id_token dưới dạng một claim; khi nhận token, bạn kiểm tra claim nonce có bằng chuỗi mình đã gửi không, nhờ đó một id_token cũ bị phát lại sẽ không qua được vòng kiểm tra. Còn code_verifier chống việc authorization code bị đánh cắp giữa đường như đã nói ở trên. Ba lớp này độc lập: có PKCE mà bỏ state thì vẫn dính tấn công đăng nhập ép buộc, có state mà bỏ nonce thì id_token vẫn có thể bị phát lại, có cả state lẫn nonce mà bỏ PKCE thì code vẫn bị đánh cắp. Công cụ sinh cả ba cùng lúc từ một nguồn ngẫu nhiên để bạn không quên cái nào.

Triển khai thực tế: lưu verifier ở đâu và vì sao hay dính invalid_grant

Câu hỏi đầu tiên khi đưa PKCE vào sản phẩm là cất code_verifier ở đâu trong lúc chờ người dùng đăng nhập xong. Với ứng dụng một trang, sessionStorage là lựa chọn hợp lý: nó chỉ sống trong một tab, tự xóa khi đóng tab, và không bị gửi kèm request như cookie. Đừng đặt vào cookie thiếu cờ HttpOnly, vì cookie loại đó vừa đọc được bằng JavaScript vừa bị gửi kèm mọi request tới miền của bạn, tức là vừa lộ vừa dư thừa. Với ứng dụng di động, chỗ đúng là Keychain trên iOS và Keystore trên Android, không phải file cấu hình hay thư viện lưu tùy chọn thường. Nhớ xóa verifier ngay sau khi đổi token xong. Câu hỏi thứ hai là thời gian: authorization code có tuổi thọ rất ngắn, phần lớn nhà cung cấp đặt trong khoảng 30 đến 60 giây và chỉ dùng được một lần, dùng lần thứ hai thì nhiều nhà cung cấp còn thu hồi luôn token đã cấp từ code đó. Lỗi bạn sẽ gặp nhiều nhất là invalid_grant, và nó gộp chung nhiều nguyên nhân nên rất khó đoán: verifier gửi lên không khớp challenge đã gửi ở bước authorize, code đã hết hạn hoặc đã dùng rồi, hoặc redirect_uri ở request đổi token không khớp tuyệt đối từng ký tự với redirect_uri ở request authorize, kể cả khác nhau đúng một dấu gạch chéo cuối. Cuối cùng, đừng nghĩ PKCE chỉ dành cho client công khai: OAuth 2.1 khuyến nghị bật PKCE cho mọi client dùng luồng authorization code, kể cả client bí mật chạy ở máy chủ, vì nó là một lớp phòng thủ rẻ và không xung đột với client_secret.

Câu hỏi thường gặp (FAQ)

Công cụ có gửi code_verifier của tôi đi đâu không?

Không. Toàn bộ giá trị sinh ngẫu nhiên ngay trong trình duyệt bằng Web Crypto API. Không có request nào rời khỏi máy bạn, không lưu vào localStorage, không ghi log. Đóng tab là mất, muốn giữ thì phải chép ra trước.

Nên chọn độ dài code_verifier bao nhiêu?

RFC 7636 cho phép từ 43 đến 128 ký tự. Với tập 66 ký tự, mỗi ký tự mang khoảng 6,04 bit nên 43 ký tự đã vượt mức khuyến nghị 256 bit entropy. Mặc định 96 ký tự cho khoảng 580 bit, dư dả mà vẫn ngắn hơn giới hạn trên.

Khi nào được phép dùng plain thay vì S256?

Gần như không bao giờ. RFC 7636 nói client PHẢI dùng S256 nếu tính được SHA-256, plain chỉ dành cho môi trường không có hàm băm. Với plain, challenge bằng đúng verifier nên ai chặn được request authorize là đổi được code đánh cắp thành token.

Vì sao code_challenge luôn dài đúng 43 ký tự?

Vì SHA-256 luôn cho ra 32 byte, và 32 byte mã hóa base64 thành 44 ký tự trong đó ký tự cuối là dấu bằng dùng để đệm. Base64url bỏ toàn bộ phần đệm nên còn lại 43. Nếu chuỗi của bạn dài 44 và kết thúc bằng dấu bằng thì bạn quên bước bỏ đệm.

Tôi làm đúng hết mà máy chủ vẫn trả invalid_grant, sai ở đâu?

Ba nguyên nhân hay gặp nhất: verifier gửi ở bước đổi token không khớp challenge đã gửi ở bước authorize, authorization code đã hết hạn hoặc đã dùng một lần rồi, và redirect_uri ở hai request không khớp tuyệt đối từng ký tự kể cả dấu gạch chéo cuối.

PKCE khác JWT ở chỗ nào?

JWT là định dạng token gồm header, payload và signature, xác minh bằng chữ ký. PKCE là cơ chế bảo vệ bước đổi authorization code lấy token. Hai thứ ở hai tầng khác nhau và thường dùng chung trong một luồng OIDC. Xem token thì dùng /vi/tools/jwt-decoder, còn trang này lo bước trước đó.

Có PKCE rồi thì bỏ state được không?

Không. PKCE chống việc authorization code bị đánh cắp, còn state chống giả mạo yêu cầu chéo trang ở bước callback. Bỏ state thì kẻ tấn công vẫn có thể dụ trình duyệt nạn nhân gọi vào redirect_uri với code của tài khoản mình, khiến nạn nhân đăng nhập nhầm tài khoản.

nonce dùng để làm gì và có bắt buộc không?

nonce thuộc về OpenID Connect. Nhà cung cấp nhúng nó vào id_token dưới dạng một claim, bạn đối chiếu claim đó với chuỗi đã gửi để chặn việc một id_token cũ bị phát lại. Chỉ cần khi scope có openid, nên URL trong công cụ tự thêm nonce khi thấy scope đó.

Nên lưu code_verifier ở đâu trong lúc chờ người dùng đăng nhập?

Ứng dụng một trang dùng sessionStorage vì nó chỉ sống trong một tab và tự xóa khi đóng tab. Ứng dụng di động dùng Keychain trên iOS hoặc Keystore trên Android. Đừng đặt vào cookie không có cờ HttpOnly. Xóa ngay sau khi đổi token xong.

Có được gửi client_secret kèm request đổi token từ trình duyệt không?

Không. Mã chạy ở trình duyệt thì ai mở công cụ nhà phát triển cũng đọc được, secret nhúng vào đó coi như đã công khai. Client công khai dùng PKCE thay cho secret. Nếu nhà cung cấp bắt buộc phải có secret thì bước đổi token phải chạy ở máy chủ của bạn.

Ứng dụng của tôi chạy ở máy chủ và giữ được secret, có cần PKCE nữa không?

Nên có. OAuth 2.1 khuyến nghị bật PKCE cho mọi client dùng luồng authorization code, kể cả client bí mật. Nó là một lớp phòng thủ rẻ, không xung đột với client_secret, và giúp bạn không phải sửa lại luồng nếu sau này có thêm bản chạy trên di động.

Vì sao không dùng Math.random hoặc UUID làm code_verifier?

Math.random không phải nguồn ngẫu nhiên dùng cho mục đích bảo mật, giá trị của nó đoán được. UUID phiên bản 4 chỉ có 122 bit ngẫu nhiên dù chuỗi dài 36 ký tự, và còn chứa dấu gạch ngang phân đoạn cố định. Công cụ dùng crypto.getRandomValues và tránh cả lệch phân bố khi ánh xạ byte sang 66 ký tự.

Từ khóa liên quan

  • oauth pkce generator
  • code verifier code challenge
  • pkce là gì
  • rfc 7636
  • code_challenge_method s256
  • sinh code verifier online
  • base64url encode sha256
  • authorization code flow with pkce
  • oauth 2.0 cho spa
  • pkce cho ứng dụng di động
  • state và nonce trong oauth
  • lỗi invalid_grant oauth
  • redirect_uri không khớp
  • tạo url authorize oauth
  • đổi authorization code lấy token
  • pkce khác jwt thế nào
  • oauth 2.1 pkce bắt buộc
  • lưu code verifier sessionstorage
  • web crypto api getrandomvalues
  • pkce keycloak auth0 entra id

Công cụ Developer Tools liên quan

.env Generator

Tạo file .env và .env.example cho dự án.

.gitignore Generator

Tạo .gitignore cho Node.js, Python, Java.

API Mock Generator

Tạo mock JSON data cho API testing.

API Response Formatter

Format và phân tích API response.

API Tester

Test REST API: GET, POST, PUT, DELETE.

Postman Alternative - API Testing Tool Online với Collections, Environment & File Upload

Postman Alternative miễn phí - Test APIs với Collections, Multiple Environments, Pre-request Scripts, Collection Runner, File Upload (form-data), Tests/Assertions, Code Generation (cURL, JS, Python, Node.js). Browser-based, không cần cài đặt. Save requests, export/import collections, auto-save history. Hỗ trợ Bearer Token, Basic Auth, API Key. Hoàn hảo cho API development và testing.

Swagger API Tester - Test API với OpenAPI/Swagger Spec & Authentication Online

Swagger API Tester miễn phí - Import OpenAPI/Swagger specification và test API endpoints với đầy đủ authentication (Bearer Token/JWT, Basic Auth, API Key). Hỗ trợ OpenAPI 3.0, Swagger 2.0, auto-parse endpoints, parameters, request body. Giao diện như Swagger UI với color-coded methods, grouped endpoints, real-time testing. Hoàn hảo cho API development, testing, debugging secured APIs.

Base Converter

Chuyển đổi Binary, Hex, Base32.

Base64 Encoder

Mã hóa/giải mã Base64.

Binary Converter

Chuyển đổi Decimal, Binary, Hex.

Box Shadow Generator

Tạo CSS box-shadow trực quan.

Chmod Calculator

Tính quyền file Linux.

Dịch vụ của Tấn Phát Digital

Đang xây sản phẩm và cần thêm người làm phần nặng?

Gói giải pháp doanh nghiệp

Nền tảng custom cho ngân hàng, y tế và sàn B2B, chuẩn ISO 27001, GDPR, PCI-DSS, SLA 99.99%.

Từ 50.000.000đXem chi tiết →

Dịch vụ phát triển Blockchain & Web3

Smart contract, dApp và NFT marketplace đa chuỗi, audit bảo mật đầy đủ trước khi lên mainnet.

Từ 50.000.000đXem chi tiết →

Dịch vụ thiết kế website tại Hồ Chí Minh

Website doanh nghiệp, bán hàng và đặt lịch, chuẩn SEO ngay từ cấu trúc, tốc độ tải dưới 3 giây.

Từ 5.000.000đXem chi tiết →

Dịch vụ thiết kế landing page

Trang đích riêng cho từng chiến dịch quảng cáo, tỷ lệ chuyển đổi 3–8%, bàn giao trong 5–21 ngày.

Từ 3.000.000đXem chi tiết →

Tư vấn và báo giá miễn phí trong 24 giờ. Xem toàn bộ dịch vụ

Zalo
Facebook
Tấn Phát Digital
Zalo
Facebook