> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-quickstart-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> This guide demonstrates how to integrate Auth0 with any new or existing Go web application.

# Add Login to your Go Application

export const LoggedInForm = ({sampleApp}) => {
  const LS_APPS_KEY = "auth_demo_apps";
  const LS_APP_CFG_KEY = "auth_demo_app_cfg";
  const CHANNEL = "auth_flows_sync_v1";
  const mkChannel = () => new BroadcastChannel(CHANNEL);
  function uid() {
    return Math.random().toString(36).slice(2) + Date.now().toString(36);
  }
  function loadApps() {
    const raw = localStorage.getItem(LS_APPS_KEY);
    if (raw) return JSON.parse(raw);
    const seeded = [{
      id: "mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai",
      name: "Default App"
    }];
    localStorage.setItem(LS_APPS_KEY, JSON.stringify(seeded));
    return seeded;
  }
  function saveApps(apps) {
    localStorage.setItem(LS_APPS_KEY, JSON.stringify(apps));
  }
  function loadCfg() {
    const raw = localStorage.getItem(LS_APP_CFG_KEY);
    return raw ? JSON.parse(raw) : {};
  }
  function saveCfg(cfg) {
    localStorage.setItem(LS_APP_CFG_KEY, JSON.stringify(cfg));
  }
  const RightChevron = ({className = "w-5 h-5", ...props}) => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className} {...props}>
      <polyline points="9 18 15 12 9 6" />
    </svg>;
  const LightningIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M24.971 30.152H7.088c-1.786 0-2.745-2.103-1.574-3.453l19.07-21.988c1.33-1.532 3.835-.4 3.569 1.607L24.97 30.152z" />
      <path fillRule="evenodd" clipRule="evenodd" className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M23.201 17.885h17.885c1.787 0 2.746 2.102 1.575 3.453l-19.073 21.99c-1.33 1.532-3.835.4-3.568-1.607L23.2 17.885z" />
    </svg>;
  const LayersIcon = () => <svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path className="fill-[#3F59E4] dark:fill-[#99A7F1]" d="M34.54 29.135l6.373 3.183c1.566.782 1.566 3.017 0 3.8l-14.815 7.396a4.623 4.623 0 01-4.125 0L7.174 36.12c-1.565-.782-1.565-3.017 0-3.798l6.532-3.214" />
      <path className="fill-[#AAB6F3] dark:fill-[#3449BA]" d="M34.54 18.86l6.373 3.183c1.566.782 1.566 3.016 0 3.8L26.098 33.24a4.623 4.623 0 01-4.125 0L7.174 25.843c-1.565-.781-1.565-3.016 0-3.798l6.33-3.164" />
      <path className="fill-[#CFD6F8] dark:fill-[#22307C]" d="M21.94 23.058L7.306 15.745c-1.62-.81-1.62-3.123 0-3.932l14.631-7.319a4.693 4.693 0 014.194 0l14.648 7.319c1.622.81 1.62 3.124 0 3.932L26.13 23.058c-1.321.66-2.873.66-4.191 0z" />
    </svg>;
  const GithubIcon = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-5 h-5">
      <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
    </svg>;
  function IconTile({children}) {
    return <div className="
          shrink-0 grid place-items-center w-10 h-10 rounded-lg
          bg-indigo-50 ring-1 ring-indigo-200/60
          dark:bg-indigo-950/40 dark:ring-white/10
        ">
        {children}
      </div>;
  }
  function Card({className = "", children}) {
    return <div className={`rounded-2xl shadow-sm ring-1 ring-zinc-200 dark:ring-zinc-800 ${className}`}>{children}</div>;
  }
  function Button({variant = "primary", type = "button", onClick, children}) {
    const base = "inline-flex items-center justify-center gap-2 h-10 px-4 rounded-xl font-medium transition";
    let styles = "";
    if (variant === "primary") {
      styles = "mint-bg-indigo-600 text-white hover:mint-bg-indigo-700";
    } else if (variant === "outline") {
      styles = "border border-zinc-300 dark:border-zinc-700 mint-bg-transparent hover:mint-bg-zinc-50 dark:hover:mint-bg-zinc-800";
    } else if (variant === "ghost") {
      styles = "hover:mint-bg-zinc-100 dark:hover:mint-bg-zinc-800";
    }
    return <button type={type} onClick={onClick} className={`${base} ${styles}`}>
        {children}
      </button>;
  }
  function Input({id, label, value, onChange, placeholder, name}) {
    return <label className="block space-y-1">
        <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
        <input id={id} name={name} className="w-full h-11 px-3 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder={placeholder} value={value} onChange={e => onChange(e.target.value)} />
      </label>;
  }
  function Select({label, value, onChange, options}) {
    return <label className="block space-y-1 max-w-[300px]">
        <span className="text-sm text-zinc-700 dark:text-zinc-300">{label}</span>
        <div className="relative">
          <select className="w-full h-11 appearance-none px-3 pr-9 rounded-xl border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500" value={value} onChange={e => onChange(e.target.value)}>
            <optgroup label="Generic Applications">
              {options.map(o => <option key={o.id} value={o.id}>
                  {o.name}
                </option>)}
            </optgroup>
          </select>
          <svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-zinc-500" viewBox="0 0 24 24">
            <path d="M7 10l5 5 5-5z" fill="currentColor" />
          </svg>
        </div>
      </label>;
  }
  function Toast({open, onClose, children}) {
    useEffect(() => {
      if (!open) return;
      const t = setTimeout(onClose, 2200);
      return () => clearTimeout(t);
    }, [open, onClose]);
    return <div className={`fixed right-4 top-4 z-50 transition ${open ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-2 pointer-events-none"}`}>
        <div className="flex items-center gap-2 rounded-xl shadow ring-1 ring-emerald-200 bg-white dark:bg-zinc-900 px-4 py-2">
          <span className="w-1.5 h-8 rounded-l bg-emerald-500" />
          <svg className="w-5 h-5 text-emerald-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
            <path d="M20 6L9 17l-5-5" />
          </svg>
          <span className="text-sm text-zinc-900 dark:text-zinc-100">{children}</span>
        </div>
      </div>;
  }
  function Flows() {
    const [route, setRoute] = useState("menu");
    const [apps, setApps] = useState(loadApps());
    const [cfg, setCfg] = useState(loadCfg());
    const [selected, setSelected] = useState(apps[0]?.id || "");
    const [toast, setToast] = useState(false);
    const [bc] = useState(() => mkChannel());
    useEffect(() => {
      if (!apps.find(a => a.id === selected)) {
        setSelected(apps[0]?.id || "");
      }
    }, [apps, selected]);
    useEffect(() => {
      const onMsg = e => {
        const {type, payload} = e.data || ({});
        switch (type) {
          case "NAV":
            setRoute(payload.route);
            break;
          case "SELECT":
            setSelected(payload.appId);
            break;
          case "APPS_UPDATED":
            setApps(loadApps());
            break;
          case "CFG_UPDATED":
            setCfg(loadCfg());
            setToast(true);
            break;
          default:
            break;
        }
      };
      bc.addEventListener("message", onMsg);
      return () => bc.removeEventListener("message", onMsg);
    }, [bc]);
    const nav = nextRoute => {
      setRoute(nextRoute);
      bc.postMessage({
        type: "NAV",
        payload: {
          route: nextRoute
        }
      });
    };
    const selectApp = appId => {
      setSelected(appId);
      bc.postMessage({
        type: "SELECT",
        payload: {
          appId
        }
      });
    };
    const onCreate = name => {
      const id = uid();
      const next = [...apps, {
        id,
        name: name || "Untitled"
      }];
      setApps(next);
      saveApps(next);
      bc.postMessage({
        type: "APPS_UPDATED"
      });
      selectApp(id);
      nav("integrate");
    };
    const onSaveCfg = (appId, data) => {
      const next = {
        ...cfg,
        [appId]: data
      };
      setCfg(next);
      saveCfg(next);
      setToast(true);
      bc.postMessage({
        type: "CFG_UPDATED"
      });
    };
    return <div>
        {route === "menu" && <Menu onCreate={() => nav("create")} onIntegrate={() => nav("integrate")} />}

        {route === "create" && <CreateForm onCancel={() => nav("menu")} onSave={onCreate} />}

        {route === "integrate" && <IntegrateForm apps={apps} selected={selected} onSelect={selectApp} saved={cfg[selected]} onSave={data => onSaveCfg(selected, data)} onCancel={() => nav("menu")} />}

        <Toast open={toast} onClose={() => setToast(false)}>
          Successfully saved your changes.
        </Toast>
      </div>;
  }
  function Menu({onCreate, onIntegrate}) {
    return <ul className="space-y-4 list-none login_list">
        <li className="list-none !px-0">
          <button onClick={onCreate} className="w-full text-left">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <LightningIcon />
                  </IconTile>
                  <h2 className="text-lg">Create a new application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </button>
        </li>
        <li className="list-none !px-0">
          <button onClick={onIntegrate} className="w-full text-left">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <LayersIcon />
                  </IconTile>
                  <h2 className="text-lg">Integrate with an existing application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </button>
        </li>
        <li className="list-none !px-0">
          <a className="no_external_icon block" href={sampleApp ? sampleApp : "/"} target="_blank" rel="noreferrer">
            <Card className="p-5 hover:shadow-md transition">
              <div className="flex items-center justify-between">
                <div className="flex items-center gap-4">
                  <IconTile>
                    <GithubIcon />
                  </IconTile>
                  <h2 className="text-lg">View a sample application</h2>
                </div>
                <RightChevron className="w-4 h-4 text-zinc-500" />
              </div>
            </Card>
          </a>
        </li>
      </ul>;
  }
  function CreateForm({onSave, onCancel}) {
    const [name, setName] = useState("");
    return <div className="space-y-6">
        <Input id="app-name" label="Application Name" placeholder="My App" value={name} onChange={setName} />
        <p className="text-sm text-zinc-500">You can change this later in the application settings.</p>
        <div className="flex gap-3">
          <Button onClick={() => onSave(name)}>Save</Button>
          <Button variant="outline" onClick={onCancel}>
            Cancel
          </Button>
        </div>
      </div>;
  }
  function IntegrateForm({apps, selected, onSelect, saved, onSave, onCancel}) {
    const [callbacks, setCallbacks] = useState(saved?.callbacks ?? "");
    const [logouts, setLogouts] = useState(saved?.logouts ?? "");
    const [origins, setOrigins] = useState(saved?.origins ?? "");
    useEffect(() => {
      setCallbacks(loadCfg()[selected]?.callbacks ?? "");
      setLogouts(loadCfg()[selected]?.logouts ?? "");
      setOrigins(loadCfg()[selected]?.origins ?? "");
    }, [selected]);
    return <div className="space-y-6">
        <div>
          <span className="block text-sm text-zinc-600 dark:text-zinc-300 mb-1">Select your Application</span>
          <Select label="" value={selected} onChange={onSelect} options={apps} />
        </div>

        <form className="space-y-4" onSubmit={e => {
      e.preventDefault();
      onSave({
        callbacks,
        logouts,
        origins
      });
    }}>
          <Input id="callbacks" name="callbacks" label="Callback URLs" placeholder="http://localhost:3000" value={callbacks} onChange={setCallbacks} />
          <Input id="logout" name="allowed_logout_urls" label="Logout URLs" placeholder="http://localhost:3000" value={logouts} onChange={setLogouts} />
          <Input id="origins" name="web_origins" label="Allowed Web Origins" placeholder="http://localhost:3000" value={origins} onChange={setOrigins} />

          <div className="flex gap-3 pt-2">
            <Button type="submit">Save</Button>
            <Button variant="outline" type="button" onClick={onCancel}>
              Cancel
            </Button>
          </div>
        </form>
      </div>;
  }
  return <div className="w-full mx-auto py-8">
      <Flows />
    </div>;
};

export const SignUpForm = () => {
  return <div className="flex flex-col gap-2 items-center h-full">
      <img noZoom src="/docs/img/quickstarts/action_hero_dashboard.svg" alt="Sign up for an Auth0 account" style={{
    width: "250px",
    height: "250px"
  }} />
      <span className="text-center" style={{
    width: "400px"
  }}>
        Sign up for an{" "}
        <a href="https://auth0.com/signup" target="_blank" rel="noopener noreferrer">
          Auth0 account
        </a>{" "}
        or{" "}
        <span className="font-semibold text-primary cursor-pointer" onClick={() => console.log("log in")}>
          log in
        </span>{" "}
        to your existing account to integrate directly with your own tenant.
      </span>
      <button onClick={() => console.log("sign up")} className="bg-primary dark:bg-primary-light text-white dark:text-black px-4 py-2 rounded-md mt-4 font-medium" style={{
    width: "140px"
  }}>
        Sign up
      </button>
    </div>;
};

export const SideMenuSectionItem = ({id, children}) => {
  return <div id={`side-menu-item-${id}`} className="recipe-side-menu-item flex flex-col w-full h-full">
      {children}
    </div>;
};

export const SideMenu = ({sections, children}) => {
  const [visibleSection, setVisibleSection] = useState(sections[0]?.id ?? null);
  const checkVisibility = () => {
    let currentVisible = null;
    const viewportHeight = window.innerHeight;
    const scrollY = window.scrollY;
    sections.forEach(({id}) => {
      const section = document.getElementById(id);
      if (section) {
        const rect = section.getBoundingClientRect();
        const sectionTop = rect.top + scrollY;
        const sectionBottom = sectionTop + rect.height;
        const multiplier = viewportHeight > 1600 ? 0.34 : 0.22;
        if (scrollY + viewportHeight * multiplier >= sectionTop && scrollY <= sectionBottom) {
          currentVisible = id;
        }
      }
    });
    if (currentVisible && currentVisible !== visibleSection) {
      setVisibleSection(currentVisible);
    }
  };
  useEffect(() => {
    const throttledCheck = () => {
      setTimeout(checkVisibility, 100);
    };
    checkVisibility();
    window.addEventListener("scroll", throttledCheck);
    return () => {
      window.removeEventListener("scroll", throttledCheck);
    };
  }, [sections, visibleSection]);
  useEffect(() => {
    sections.forEach(({id}) => {
      const section = document.getElementById(id);
      const sideMenuItem = document.getElementById(`side-menu-item-${id}`);
      if (section) {
        if (id === visibleSection) {
          section.classList.add("active-section");
        } else {
          section.classList.remove("active-section");
        }
      }
      if (sideMenuItem) {
        if (id === visibleSection) {
          sideMenuItem.classList.add("active-side-menu-item");
        } else {
          sideMenuItem.classList.remove("active-side-menu-item");
        }
      }
    });
  }, [visibleSection, sections]);
  return <div className="recipe-side-menu sticky px-2 py-1" style={{
    height: "calc(100vh - 7rem)",
    top: "7rem",
    scrollMarginTop: "var(--scroll-mt)"
  }}>
      {children.map(child => {
    if (child.props.id === visibleSection) {
      return child;
    }
    return null;
  })}
    </div>;
};

export const Section = ({id, title, stepNumber, children, isSingleColumn = false}) => {
  return <div id={id} className={`recipe-section flex flex-col transition-opacity duration-200`}>
      {}
      <Step title={title} stepNumber={stepNumber} titleSize="h3">
        {children}
      </Step>
    </div>;
};

export const Content = ({title, children}) => {
  return <div className="recipe-content flex flex-col">
      {title && <h1 className="text-3xl">{title}</h1>}
      {children}
    </div>;
};

export const Recipe = ({children, isSingleColumn = false}) => {
  return <div className={`pl-4 recipe-container mx-auto grid grid-cols-1 gap-10 relative ${isSingleColumn ? "md:grid-cols-1" : "md:grid-cols-2"}`}>
      {children}
    </div>;
};

export const sections = [{
  id: "configure-auth0",
  title: "Configure Auth0"
}, {
  id: "install-dependencies",
  title: "Install dependencies"
}, {
  id: "configure-the-environment-variables",
  title: "Configure the environment variables"
}, {
  id: "configure-oauth2-and-openid-connect-packages",
  title: "Configure OAuth2 and OpenID Connect packages"
}, {
  id: "set-up-your-application-routes",
  title: "Set up your application routes"
}, {
  id: "add-login-to-your-application",
  title: "Add login to your application"
}, {
  id: "handle-authentication-callback",
  title: "Handle authentication callback"
}, {
  id: "display-user-profile-information",
  title: "Display user profile information"
}, {
  id: "add-logout-to-your-application",
  title: "Add logout to your application"
}, {
  id: "protect-routes",
  title: "Protect routes"
}, {
  id: "serve-your-application",
  title: "Serve your application"
}];

<Recipe>
  <Content>
    Auth0 allows you to add authentication and gain access to user profile information in your application. This guide
    demonstrates how to integrate Auth0 with any new or existing Go web application.

    <Section id={sections[0].id} title={sections[0].title} stepNumber="1">
      To use Auth0 services, you’ll need to have an application set up in the Auth0 Dashboard. The Auth0 application is
      where you will configure how you want authentication to work for the project you are developing.

      ### Configure an application

      Use the interactive selector to create a new Auth0 application or select an existing application that represents
      the project you want to integrate with. Every application in Auth0 is assigned an alphanumeric, unique client ID
      that your application code will use to call Auth0 APIs through the SDK.

      Any settings you configure using this quickstart will automatically update for your Application in the [Dashboard](https://manage.auth0.com/dashboard/us/auth0-dsepaid/), which is where you can manage your Applications in the future.

      If you would rather explore a complete configuration, you can view a sample application instead.

      ### Configure Callback URLs

      A callback URL is a URL in your application that you would like Auth0 to redirect users to after they have
      authenticated. If not set, users will not be returned to your application after they log in.

      <Info>
        If you are following along with our sample project, set this to
        `http://localhost:3000/callback`.
      </Info>

      ### Configure Logout URLs

      A logout URL is a URL in your application that you would like Auth0 to redirect users to after they have logged
      out. If not set, users will not be able to log out from your application and will receive an error.

      <Info>
        If you are following along with our sample project, set this to `http://localhost:3000`.
      </Info>
    </Section>

    <Section id={sections[1].id} title={sections[1].title} stepNumber="2">
      Create a `go.mod` file to list all the dependencies in your application.

      To integrate Auth0 in a Go application, add the `coreos/go-oidc/v3` and `x/oauth2`
      packages.

      In addition to the OIDC and OAuth2 packages, add `joho/godotenv`, `gin-gonic/gin`, and
      `gin-contrib/sessions`.

      <Info>
        This example uses `gin` for routing, but you can use whichever router you want.
      </Info>

      Save the `go.mod` file with the necessary dependencies and install them using the following command in
      your terminal:

      ```text lines
      go mod download
      ```
    </Section>

    <Section id={sections[2].id} title={sections[2].title} stepNumber="3">
      You must set the following environment variables in `.env` within the root of your project directory:

      * **AUTH0\_DOMAIN**: The domain of your Auth0 tenant. Find your Auth0 Domain in the Auth0 Dashboard under
        your Application's Settings in the Domain field. For custom domains, set this to the value of your custom domain instead.
      * **AUTH0\_CLIENT\_ID**: The ID of the Auth0 Application you set up earlier in this quickstart. Find this in
        the Auth0 Dashboard under your Application's Settings in the Client ID field.
      * **AUTH0\_CLIENT\_SECRET**: The Secret of the Auth0 Application you set up earlier in this quickstart. Find
        this in the Auth0 Dashboard under your Application's Settings in the Client Secret field.
      * **AUTH0\_CALLBACK\_URL**: The URL used by Auth0 to redirect the user after successful authentication.
    </Section>

    <Section id={sections[3].id} title={sections[3].title} stepNumber="4">
      Next, configure the OAuth2 and OpenID Connect packages.

      Create a file called `auth.go` in the `platform/authenticator` folder. In this package,
      create a method to configure and return [OAuth2](https://godoc.org/golang.org/x/oauth2) and [OIDC](https://godoc.org/github.com/coreos/go-oidc) clients, and another one to verify an ID Token.
    </Section>

    <Section id={sections[4].id} title={sections[4].title} stepNumber="5">
      Create a file called `router.go` in the `platform/router` folder. In this package, create a
      method to configure and return our routes using [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin). You will be passing an instance of
      `Authenticator` to the method, for use with the `login` and `callback` handlers.
    </Section>

    <Section id={sections[5].id} title={sections[5].title} stepNumber="6">
      For the user to authenticate themselves, we need to create a handler function to handle the `/login`
      route.

      Create a file called `login.go` in the `web/app/login` folder, and add a
      `Handler` function. Upon executing the handler, the user will be redirected to Auth0 where they can
      enter their credentials.

      To call the `/login` route, add a link to `/login` in the `home.html` template
      located in the `web/template` directory.
    </Section>

    <Section id={sections[6].id} title={sections[6].title} stepNumber="7">
      Once users have authenticated using Auth0's Universal Login Page, they will return to the app at the
      `/callback` route.

      Create a file called `callback.go` in the `web/app/callback` folder, and add a
      `Handler` function.

      This handler will take the `code` query string, provided by Auth0, and exchange it for an ID token and
      an access token.

      If the ID token is valid, it will store the profile information and access token in the session. The profile
      information is based on the claims contained in the ID token. Session storage allows the application to access
      that information as needed.
    </Section>

    <Section id={sections[7].id} title={sections[7].title} stepNumber="8">
      Now that your users can log in, you will likely want to be able to retrieve and use the profile information associated with authenticated users.

      You can access that profile information, such as their nickname or profile picture, through the
      `profile` that was stored in the session previously.

      Create a handler for the `/user` endpoint in `web/app/user/user.go` and return the
      corresponding HTML file. As the `profile` is being passed to `ctx.HTML()`, you can access
      the profile information such as `picture` and `nickname` inside that same HTML file.

      An example of such an HTML file could look like the example below, but you can retrieve any profile information,
      including custom claims.
    </Section>

    <Section id={sections[8].id} title={sections[8].title} stepNumber="9">
      To log the user out, clear the data from the session and redirect the user to the Auth0 logout endpoint. You can
      find more information about this in the [logout
      documentation](https://auth0.com/docs/logout).

      Create a file called `logout.go` in the folder `web/app/logout`, and add the function
      `Handler` to redirect the user to Auth0's logout endpoint.

      The `returnTo` URL needs to be in the list of Allowed Logout URLs in the settings section of the
      application, For more information, see [Redirect Users After Logout](https://auth0.com/docs/logout/guides/redirect-users-after-logout).

      Create a file called `user.js` in the folder `web/static/js`, and add the code to remove
      the cookie from a logged-in user.
    </Section>

    <Section id={sections[9].id} title={sections[9].title} stepNumber="10">
      Recommended practice dictates certain routes are accessible only to authenticated users. When unauthenticated
      users try accessing protected routes, your application should redirect them.

      In this case, you will implement middleware to hook into the HTTP request. The middleware function determines if
      the request should route to the endpoint handler or block the request.

      Create a file called `isAuthenticated.go` in `platform/middleware` and add a function that
      checks if the user is authenticated or not based on the `profile` session key. If the user is not
      authenticated, the middleware will redirect the user to the root of the application.

      With the middleware created, we can set it up for any route that needs authentication by adding it to the router.
    </Section>

    <Section id={sections[10].id} title={sections[10].title} stepNumber="11">
      With both the authenticator and router configured, we can wire things up using our application's entry point.
      Inside `main.go`, create an instance of the authenticator and the router, which gets passed the
      authenticator instance.

      If you are using a `.env` file, you must call `godotenv.Load()` at the very beginning of
      the `main()` function.

      Serve your application by using the following command in your terminal:

      ```text lines
      go run main.go
      ```
    </Section>

    ## Next Steps

    Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.

    This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:

    * [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
    * [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
  </Content>

  <SideMenu sections={sections}>
    <SideMenuSectionItem id={sections[0].id}>
      <SignUpForm />
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[1].id}>
      <CodeGroup>
        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[2].id}>
      <CodeGroup>
        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[3].id}>
      <CodeGroup>
        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[4].id}>
      <CodeGroup>
        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[5].id}>
      <CodeGroup>
        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[6].id}>
      <CodeGroup>
        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[7].id}>
      <CodeGroup>
        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[8].id}>
      <CodeGroup>
        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[9].id}>
      <CodeGroup>
        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>

    <SideMenuSectionItem id={sections[10].id}>
      <CodeGroup>
        ```golang main.go lines 
        // Save this file in ./main.go

        package main

        import (
        	"log"
        	"net/http"

        	"github.com/joho/godotenv"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/router"
        )

        func main() {
        	if err := godotenv.Load(); err != nil {
        		log.Fatalf("Failed to load the env vars: %v", err)
        	}

        	auth, err := authenticator.New()
        	if err != nil {
        		log.Fatalf("Failed to initialize the authenticator: %v", err)
        	}

        	rtr := router.New(auth)

        	log.Print("Server listening on http://localhost:3000/")
        	if err := http.ListenAndServe("0.0.0.0:3000", rtr); err != nil {
        		log.Fatalf("There was an error with the http server: %v", err)
        	}
        }
        ```

        ```golang auth.go lines 
        // Save this file in ./platform/authenticator/auth.go

        package authenticator

        import (
        	"context"
        	"errors"
        	"os"

        	"github.com/coreos/go-oidc/v3/oidc"
        	"golang.org/x/oauth2"
        )

        // Authenticator is used to authenticate our users.
        type Authenticator struct {
        	*oidc.Provider
        	oauth2.Config
        }

        // New instantiates the *Authenticator.
        func New() (*Authenticator, error) {
        	provider, err := oidc.NewProvider(
        		context.Background(),
        		"https://"+os.Getenv("AUTH0_DOMAIN")+"/",
        	)
        	if err != nil {
        		return nil, err
        	}

        	conf := oauth2.Config{
        		ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
        		ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
        		RedirectURL:  os.Getenv("AUTH0_CALLBACK_URL"),
        		Endpoint:     provider.Endpoint(),
        		Scopes:       []string{oidc.ScopeOpenID, "profile"},
        	}

        	return &Authenticator{
        		Provider: provider,
        		Config:   conf,
        	}, nil
        }

        // VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken.
        func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) {
        	rawIDToken, ok := token.Extra("id_token").(string)
        	if !ok {
        		return nil, errors.New("no id_token field in oauth2 token")
        	}

        	oidcConfig := &oidc.Config{
        		ClientID: a.ClientID,
        	}

        	return a.Verifier(oidcConfig).Verify(ctx, rawIDToken)
        }
        ```

        ```golang callback.go lines 
        / Save this file in ./web/app/callback/callback.go

        package callback

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our callback.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		session := sessions.Default(ctx)
        		if ctx.Query("state") != session.Get("state") {
        			ctx.String(http.StatusBadRequest, "Invalid state parameter.")
        			return
        		}

        		// Exchange an authorization code for a token.
        		token, err := auth.Exchange(ctx.Request.Context(), ctx.Query("code"))
        		if err != nil {
        			ctx.String(http.StatusUnauthorized, "Failed to exchange an authorization code for a token.")
        			return
        		}

        		idToken, err := auth.VerifyIDToken(ctx.Request.Context(), token)
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, "Failed to verify ID Token.")
        			return
        		}

        		var profile map[string]interface{}
        		if err := idToken.Claims(&profile); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		session.Set("access_token", token.AccessToken)
        		session.Set("profile", profile)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Redirect to logged in page.
        		ctx.Redirect(http.StatusTemporaryRedirect, "/user")
        	}
        }
        ```

        ```env .env lines
        # Save this file in ./.env

        # The URL of our Auth0 Tenant Domain.
        # If you're using a Custom Domain, be sure to set this to that value instead.
        AUTH0_DOMAIN='dev-gja8kxz4ndtex3rq.us.auth0.com'

        # Our Auth0 application's Client ID.
        AUTH0_CLIENT_ID='mz9iNEIo2PHu7oeh8QRt19ndTyyCIgai'

        # Our Auth0 application's Client Secret.
        AUTH0_CLIENT_SECRET='yLTW7npKO4g1HHsCENiZbOaHHXLmhVefJxdNnXcyhOBOomZ2tgjJjSC2pMK7Swvr'

        # The Callback URL of our application.
        AUTH0_CALLBACK_URL='http://localhost:3000/callback'
        ```

        ```mod go.mod lines
        // Save this file in ./go.mod

        module 01-Login

        go 1.21

        require (
        	github.com/coreos/go-oidc/v3 v3.8.0
        	github.com/gin-contrib/sessions v0.0.5
        	github.com/gin-gonic/gin v1.9.1
        	github.com/joho/godotenv v1.5.1
        	golang.org/x/oauth2 v0.15.0
        )
        ```

        ```golang isAuthenticated.go lines
        // Save this file in ./platform/middleware/isAuthenticated.go

        package middleware

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // IsAuthenticated is a middleware that checks if
        // the user has already been authenticated previously.
        func IsAuthenticated(ctx *gin.Context) {
        	if sessions.Default(ctx).Get("profile") == nil {
        		ctx.Redirect(http.StatusSeeOther, "/")
        	} else {
        		ctx.Next()
        	}
        }
        ```

        ```golang login.go lines 
        // Save this file in ./web/app/login/login.go

        package login

        import (
        	"crypto/rand"
        	"encoding/base64"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        )

        // Handler for our login.
        func Handler(auth *authenticator.Authenticator) gin.HandlerFunc {
        	return func(ctx *gin.Context) {
        		state, err := generateRandomState()
        		if err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		// Save the state inside the session.
        		session := sessions.Default(ctx)
        		session.Set("state", state)
        		if err := session.Save(); err != nil {
        			ctx.String(http.StatusInternalServerError, err.Error())
        			return
        		}

        		ctx.Redirect(http.StatusTemporaryRedirect, auth.AuthCodeURL(state))
        	}
        }

        func generateRandomState() (string, error) {
        	b := make([]byte, 32)
        	_, err := rand.Read(b)
        	if err != nil {
        		return "", err
        	}

        	state := base64.StdEncoding.EncodeToString(b)

        	return state, nil
        }
        ```

        ```golang logout.go lines 
        // Save this file in ./web/app/logout/logout.go

        package logout

        import (
        	"net/http"
        	"net/url"
        	"os"

        	"github.com/gin-gonic/gin"
        )

        // Handler for our logout.
        func Handler(ctx *gin.Context) {
        	logoutUrl, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/v2/logout")
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	scheme := "http"
        	if ctx.Request.TLS != nil {
        		scheme = "https"
        	}

        	returnTo, err := url.Parse(scheme + "://" + ctx.Request.Host)
        	if err != nil {
        		ctx.String(http.StatusInternalServerError, err.Error())
        		return
        	}

        	parameters := url.Values{}
        	parameters.Add("returnTo", returnTo.String())
        	parameters.Add("client_id", os.Getenv("AUTH0_CLIENT_ID"))
        	logoutUrl.RawQuery = parameters.Encode()

        	ctx.Redirect(http.StatusTemporaryRedirect, logoutUrl.String())
        }
        ```

        ```golang router.go lines 
        // Save this file in ./platform/router/router.go

        package router

        import (
        	"encoding/gob"
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-contrib/sessions/cookie"
        	"github.com/gin-gonic/gin"

        	"01-Login/platform/authenticator"
        	"01-Login/platform/middleware"
        	"01-Login/web/app/callback"
        	"01-Login/web/app/login"
        	"01-Login/web/app/logout"
        	"01-Login/web/app/user"
        )

        // New registers the routes and returns the router.
        func New(auth *authenticator.Authenticator) *gin.Engine {
        	router := gin.Default()

        	// To store custom types in our cookies,
        	// we must first register them using gob.Register
        	gob.Register(map[string]interface{}{})

        	store := cookie.NewStore([]byte("secret"))
        	router.Use(sessions.Sessions("auth-session", store))

        	router.Static("/public", "web/static")
        	router.LoadHTMLGlob("web/template/*")

        	router.GET("/", func(ctx *gin.Context) {
        		ctx.HTML(http.StatusOK, "home.html", nil)
        	})
        	router.GET("/login", login.Handler(auth))
        	router.GET("/callback", callback.Handler(auth))
        	router.GET("/user", user.Handler)
        	router.GET("/logout", logout.Handler)

        	return router
        }
        ```

        ```golang user.go lines
        // Save this file in ./web/app/user/user.go

        package user

        import (
        	"net/http"

        	"github.com/gin-contrib/sessions"
        	"github.com/gin-gonic/gin"
        )

        // Handler for our logged-in user page.
        func Handler(ctx *gin.Context) {
        	session := sessions.Default(ctx)
        	profile := session.Get("profile")

        	ctx.HTML(http.StatusOK, "user.html", profile)
        }
        ```
      </CodeGroup>
    </SideMenuSectionItem>
  </SideMenu>
</Recipe>
