Add Membership to Webflow sites with Authgear

Webflow is sunsetting its native User Accounts feature, leaving many site owners searching for a new way to manage member logins and gated content. If you rely on Webflow for authentication, it’s time to explore alternatives—before your users lose access. This article shows how Authgear can seamlessly replace Webflow’s soon-to-be-retired accounts, keeping your community secure and engaged.

 min. read
Last updated:
July 4, 2025

With Webflow sunsetting its native User Accounts feature, many developers face the challenge of finding a secure, robust, and easy-to-integrate solution. Now, imagine you're building a loyalty program website—a vibrant digital haven where members effortlessly log in to check their personalized content and track their reward points. Your community is excited to explore exclusive benefits and see their progress, but with the traditional authentication method gone, how do you ensure a flawless, secure experience?

Enter Authgear. This powerful tool steps in to bridge the gap left by Webflow. Authgear’s generous free tier and versatile suite of features make it the ideal replacement for managing user authentication on your loyalty program site. Whether you’re a seasoned developer or just beginning your journey, integrating Authgear ensures your members can seamlessly log in, interact with exclusive content, and feel secure every step of the way.

In this guide, you’ll embark on a step-by-step process to integrate Authgear into your Webflow website. By the end, you’ll have learned to:

  • Create an Authgear project and an application.
  • Add Login, Logout, and Sign Up buttons that show/hide correctly.
  • Implement the core authentication logic for your Webflow site.
  • Display standard and custom user information in a protected section.
  • Create and manage gated content visible only to logged-in users.

You can check the end product of this guide in here, you can also clone the Webflow project here.

Prerequisites

  • An active Authgear account. If you don't have one, you can sign up for free.
  • A Webflow account and a project you want to add authentication to.

Step 1: Create Your Authgear Project

First, we'll create a project, which acts as a container for your applications and users.

  1. After signing into the Authgear Portal, you will be prompted to create a new project.
  2. Enter a Project Name (e.g., My Webflow Site).
  3. Complete the endpoint domain to form your unique Authgear endpoint: https://<your-project-name>.authgear.cloud. Click "Next".
Project Name
  1. Choose how you would like your end-users to login. In this tutorial, make sure we choose Email here.
  2. Add branding by uploading logo and choosing the colors you like.

Step 2: Create and Configure an Application

Now that you have a project, you need to create an application within it.

  1. In the Authgear Portal, navigate to Applications in the left-hand menu.
  2. Click the + Add Application button in the top toolbar.
  3. In the dialog, enter an Application Name (e.g., "Webflow Site") and select the Single Page Application type. Click "Save".
Select Single Page Application
  1. On the next screen, Authgear shows tutorials for various frameworks. Click Next to skip this and go to your application's configuration page.
  2. You will now be on the application configuration page. Under the URIs section, find the Authorized Redirect URIs field.
  3. Enter the root URL of your published Webflow site (e.g., https://my-awesome-site.webflow.io/). Note that the trailing "/" in the above URLs must be included.
  4. Click Save at the bottom of the page.
  5. Finally, make a note on your Client ID and Endpoint. You will need these values in a later step.
Copy Client ID and Endpoint, enter URL of Webflow site

Step 3: Add Custom Styles to Webflow

  1. In your Webflow project, go to Site Settings > Custom Code.
  2. In the Head Code section, paste the CSS styles below. These styles prevent a "flash" of content before our script has a chance to run. The script itself will be added to the footer in the next step for better page performance.
1<!-- Initial Visibility Styles -->
2<style>
3  .auth---visible, .auth---invisible {
4    visibility: hidden;   
5  }
6  .hidden {
7    display: none !important; 
8  }
9</style>
  1. Click "Save Changes".

Step 4: Add the SDK and Style Authentication Buttons

  1. In the Webflow Designer, add three Button elements to your page.
  2. Set their text to "Login", "Sign Up", and "Logout".
  3. Assign classes and IDs:
    • Login Button: Class auth---invisible, ID login-btn
    • Sign Up Button: Class auth---invisible, ID signup-btn
    • Logout Button: Class auth---visible, ID logout-btn
  4. Go back to Site Settings > Custom Code and paste the following into the Footer Code section. This includes the Authgear SDK and the initial logic for your buttons.
1<!-- Authgear Web SDK -->
2<script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
3
4<script>
5const login = () => { console.log("Login button clicked."); };
6const logout = () => { console.log("Logout button clicked."); };
7
8const addClickListeners = () => {
9  document.querySelector("#login-btn")?.addEventListener("click", login);
10  document.querySelector("#signup-btn")?.addEventListener("click", login);
11  document.querySelector("#logout-btn")?.addEventListener("click", logout);
12};
13
14window.onload = () => {
15    addClickListeners();
16};
17</script>

Step 5: Implement the Core Authentication and UI Logic

Update the Footer Code:

In your Webflow Footer Code, replace the contents of the second <script> tag with the full logic below. Remember to update the placeholder values with your credentials from Step 2.

1// --- Authgear Configuration ---
2let authgearClient = null;
3
4const configureClient = async () => {
5    authgearClient = window.authgear.default;
6    await authgearClient.configure({
7        endpoint: "<YOUR_AUTHGEAR_PROJECT_DOMAIN>",
8        clientID: "<YOUR_AUTHGEAR_APP_CLIENT_ID>",
9        sessionType: "refresh_token",
10    }).then(
11        () => { console.log("Authgear client successfully configured!"); },
12        (err) => { console.log("Failed to configure Authgear", err); }
13    );
14};
15
16// --- Authentication Functions ---
17const login = () => {
18  try {
19    console.log("Redirecting to login...");
20    const targetURL = `${window.location.origin}/`;
21    authgearClient.startAuthentication({ redirectURI: targetURL, prompt: "login" });
22  } catch (err) { console.log("Login failed", err); }
23};
24
25const logout = () => {
26  try {
27    console.log("Logging out");
28    authgearClient.logout({
29      redirectURI: window.location.origin
30    }).then(
31      () => { updateUI(); },
32      (err) => { console.log("Logout failed", err); }
33    );
34  } catch (err) { console.log("Log out failed", err); }
35};
36
37// --- UI Control ---
38const eachElement = (selector, fn) => {
39  for (let e of document.querySelectorAll(selector)) { fn(e); }
40};
41
42const updateUI = async () => {
43    const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";
44    if (isAuthenticated) {
45        eachElement(".auth---invisible", (e) => e.classList.add("hidden"));
46        eachElement(".auth---visible", (e) => {
47            e.classList.remove("hidden");
48            e.style.visibility = "visible";
49        });
50    } else {
51        if (document.body.classList.contains("auth---visible")) { window.location.replace("/"); }
52        eachElement(".auth---invisible", (e) => {
53            e.classList.remove("hidden");
54            e.style.visibility = "visible";
55        });
56        eachElement(".auth---visible", (e) => e.classList.add("hidden"));
57    }
58};
59
60// --- Event Listeners and Page Load ---
61const addClickListeners = () => {
62  document.querySelector("#login-btn")?.addEventListener("click", login);
63  document.querySelector("#signup-btn")?.addEventListener("click", login);
64  document.querySelector("#logout-btn")?.addEventListener("click", logout);
65};
66
67window.onload = async () => {
68  await configureClient();
69  addClickListeners();
70  try {
71    if (window.location.search.includes("code=")) {
72        await authgearClient.finishAuthentication();
73        window.history.replaceState({}, document.title, window.location.pathname);
74    }
75  } catch {}
76  try {
77    await authgearClient.refreshAccessToken();
78  } catch {} 
79  finally {
80    console.log("Authgear Session State:", authgearClient.sessionState);
81    updateUI();
82  }
83};

Then, you can move on to sign up as the first user:

  1. Publish your Webflow site.
  2. Open the live site URL and click "Sign Up" to create an account.
  3. After signing up, you will be redirected back, and the "Logout" button should be visible.
  4. Verify this new user exists in your Authgear Admin Portal under User Management > Users.

Step 6: Add Elements for Standard User Information

  1. In the Webflow Designer, add two Paragraph elements to your page.
  2. Assign them IDs and text:
    • First Paragraph: ID user-email, Text Membership Email:
    • Second Paragraph: ID user-email-verified, Text Verification Status:
  3. In your Footer Code, update the updateUI function to fetch and append this data.
1const updateUI = async () => {
2    const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";
3    if (isAuthenticated) {
4        eachElement(".auth---invisible", (e) => e.classList.add("hidden"));
5        eachElement(".auth---visible", (e) => {
6            e.classList.remove("hidden");
7            e.style.visibility = "visible";
8        });
9        // --- THIS PART IS NEW ---
10        try {
11            const userInfo = await authgearClient.fetchUserInfo();
12            document.getElementById("user-email").textContent += ` ${userInfo.email}`;
13            document.getElementById("user-email-verified").textContent += ` ${userInfo.emailVerified ? "Verified" : "Not Verified"}`;
14        } catch (error) { console.error("Failed to fetch user info:", error); }
15        // --- END NEW PART ---
16    } else { // ... else logic from step 5
17        if (document.body.classList.contains("auth---visible")) { window.location.replace("/"); }
18        eachElement(".auth---invisible", (e) => {
19            e.classList.remove("hidden");
20            e.style.visibility = "visible";
21        });
22        eachElement(".auth---visible", (e) => e.classList.add("hidden"));
23    }
24};

Step 7: Add and Display Custom Attributes

7a. Create, Configure, and Assign a Custom Attribute

  1. Define the Attribute:
    1. In the Authgear Admin Portal, navigate to User Profile > Custom Attributes.
    2. Click "+ Add New Attribute".
    3. Configure it: Name points_collected, Type Number. Click "Save".
    4. In the list, set Token Bearer Access Right and End-user Access Right to Read-only.
Add Custom Attributes
  1. Assign a Value to Your User
    1. Navigate to User Management > Users, and click on your test user.
    2. In the Profile Tab, scroll down to Custom Attributes.
    3. Enter a number (e.g., 50) in the Points Collected field and click "Save".
Assign Custom Attributes

7b. Display the Custom Attribute in Webflow

  1. In the Webflow Designer, add a new Paragraph element to your page.
  2. Give it the ID points-collected and set its text to FlowPoints Collected:.
  3. In your Footer Code, update the updateUI function again to fetch and display this value.
1const updateUI = async () => {
2    // ...
3    if (isAuthenticated) {
4        // ...
5        try {
6            const userInfo = await authgearClient.fetchUserInfo();
7            document.getElementById("user-email").textContent += ` ${userInfo.email}`;
8            document.getElementById("user-email-verified").textContent += ` ${userInfo.emailVerified ? "Verified" : "Not Verified"}`;
9            
10            // --- THIS PART IS NEW ---
11            const points = userInfo.customAttributes?.points_collected ?? 0;
12            document.getElementById("points-collected").textContent += ` ${points}`;
13            // --- END NEW PART ---
14
15        } catch (error) { console.error("Failed to fetch user info:", error); }
16    }
17    // ...
18};

Step 8: Protect Content

8a. Protect a Section of a Page

  1. In the Webflow Designer, add a Div Block to your page for the "logged out" view.
    • Give it the class auth---invisible.
    • Inside, add a Paragraph with the text "Please login to see this locked content".
    • Add a Button with the text "Login to View" and the class content-button.
  2. Add a second Div Block for the "logged in" view.
    • Give it the class auth---visible.
    • Drag the three paragraph elements from Steps 6 and 7 inside this div.
  3. Finally, add a click listener for the new content-button.
1const addClickListeners = () => {
2  document.querySelector("#login-btn")?.addEventListener("click", login);
3  document.querySelector("#signup-btn")?.addEventListener("click", login);
4  document.querySelector("#logout-btn")?.addEventListener("click", logout);
5  // This line is new
6  document.querySelector(".content-button")?.addEventListener("click", login);
7};

8b. Protect an Entire Page

  1. Create a new page in Webflow (e.g., "locked-content").
  2. In the Navigator panel, select the Body element.
  3. In the Style Panel (S), give the Body the class auth---visible. Our script will now automatically redirect any unauthenticated users from this page.

Final Code

Here is the complete, final script to be placed in your Webflow project's Footer Code.

1<!-- Authgear Web SDK -->
2<script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
3
4<script>
5let authgearClient = null;
6
7const configureClient = async () => {
8    authgearClient = window.authgear.default;
9    await authgearClient.configure({
10        endpoint: "<YOUR_AUTHGEAR_PROJECT_DOMAIN>",
11        clientID: "<YOUR_AUTHGEAR_APP_CLIENT_ID>",
12        sessionType: "refresh_token",
13    }).then(
14        () => { console.log("Authgear client successfully configured!"); },
15        (err) => { console.log("Failed to configure Authgear", err); }
16    );
17};
18
19const login = () => {
20  try {
21    console.log("Redirecting to login...");
22    const targetURL = `${window.location.origin}/`;
23    authgearClient.startAuthentication({ redirectURI: targetURL, prompt: "login" });
24  } catch (err) { console.log("Login failed", err); }
25};
26
27const logout = () => {
28  try {
29    console.log("Logging out");
30    authgearClient.logout({
31      redirectURI: window.location.origin
32    }).then(
33      () => {
34        // logged out successfully
35        updateUI();
36      },
37      (err) => {
38        // failed to logout
39        console.log("Logout failed", err);
40      }
41    );
42  } catch (err) {
43    console.log("Log out failed", err);
44  }
45};
46
47const eachElement = (selector, fn) => {
48  for (let e of document.querySelectorAll(selector)) { fn(e); }
49};
50
51const updateUI = async () => {
52  const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";
53
54  if (isAuthenticated) {
55    eachElement(".auth---invisible", (e) => e.classList.add("hidden"));
56    eachElement(".auth---visible", (e) => {
57      e.classList.remove("hidden");
58      e.style.visibility = "visible";
59    });
60
61    try {
62      const userInfo = await authgearClient.fetchUserInfo();
63      // Clear previous data to prevent duplication on UI refreshes
64      document.getElementById("user-email").textContent = 'Membership Email:';
65      document.getElementById("user-email-verified").textContent = 'Verification Status:';
66      document.getElementById("points-collected").textContent = 'FlowPoints Collected:';
67      
68      // Append new data
69      document.getElementById("user-email").textContent += ` ${userInfo.email}`;
70      document.getElementById("user-email-verified").textContent += ` ${userInfo.emailVerified ? "Verified" : "Not Verified"}`;
71      const points = userInfo.customAttributes?.points_collected ?? 0;
72      document.getElementById("points-collected").textContent += ` ${points}`;
73    } catch (error) { console.error("Failed to fetch user info:", error); }
74
75  } else {
76    if (document.body.classList.contains("auth---visible")) {
77        window.location.replace("/");
78    }
79    eachElement(".auth---invisible", (e) => {
80        e.classList.remove("hidden");
81        e.style.visibility = "visible";
82    });
83    eachElement(".auth---visible", (e) => e.classList.add("hidden"));
84  }
85};
86
87const addClickListeners = () => {
88  document.querySelector("#login-btn")?.addEventListener("click", login);
89  document.querySelector("#signup-btn")?.addEventListener("click", login);
90  document.querySelector("#logout-btn")?.addEventListener("click", logout);
91  document.querySelector(".content-button")?.addEventListener("click", login);
92};
93
94window.onload = async () => {
95  await configureClient();
96  addClickListeners();
97
98  try {
99    if (window.location.search.includes("code=")) {
100        await authgearClient.finishAuthentication();
101        window.history.replaceState({}, document.title, window.location.pathname);
102    }
103  } catch {}
104
105  // `refreshAccessToken` ensures the session information is up-to-date.
106  try {
107    await authgearClient.refreshAccessToken();
108  } catch {
109    // It's normal for this to fail for logged-out users. We can safely ignore the error.
110  } finally {
111    // Update the UI. This `finally` block runs regardless of whether
112    // the user was logged in or not, ensuring the UI is always correct.
113    console.log("Authgear Session State:", authgearClient.sessionState);
114    updateUI();
115  }
116};
117</script>

Conclusion

By following this guide, you’ve seen how Authgear can seamlessly fill the gap left by Webflow’s native User Accounts, enabling you to offer secure, intuitive authentication and personalized experiences for your users. With features like easy integration, customizable UI, and robust user management, Authgear empowers you to protect your content and build thriving communities with confidence.

Ready to secure your Webflow site and delight your users? Sign up for Authgear for free and start building today!

Preferences

Privacy is important to us, so you have the option of disabling certain types of storage that may not be necessary for the basic functioning of the website. Blocking categories may impact your experience on the website.

Accept all cookies

These items are required to enable basic website functionality.

Always active

These items are used to deliver advertising that is more relevant to you and your interests.

These items allow the website to remember choices you make (such as your user name, language, or the region you are in) and provide enhanced, more personal features.

These items help the website operator understand how its website performs, how visitors interact with the site, and whether there may be technical issues.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.