#How to secure frontend with authorizer

169 messages · Page 1 of 1 (latest)

still epoch
#

If I deploy the langflow and authorizer templates to two instances, how do I set it up so that I need to log into authorizer first to be able to see the langflow interface?

How to set it up in general for any github package with a webserver so that it is protected through some interace or authorizer? Can I change the URL? Is there a secure forwarding?

Project ID: c7df755c-dc65-45a0-84a6-2c9a80edc415
ProjectID: 855a6c19-b8d9-4df8-a5d2-e8ef9f7b1637

daring elmBOT
#

Project ID: 2623fad8-b2a5-4b41-89c5-cb8771b12356

ashen mason
#

if you've solved this thread we would all appreciate it if you could tell us how it was solved, for anyone in the future who may have this question too

still epoch
#

No I don't know how to solve this myself ^^

ashen mason
#

you marked this as solved, was that a miss-click?

still epoch
#

yeah, can I delete the thread and reopen it?

ashen mason
#

fixed

#

but I'll admit I don't know how to solve this issue for you, but I'll look into it and see what I can find, no promises though

still epoch
ashen mason
#

I I'll look into it, but again no promises

still epoch
#

okay thanks, wouldbe great if you can find it out

ashen mason
#

okay so unfortunately you have the wrong idea about what authorizer is, its not something that you can just stick infront of anything web based and add a login screen to, it would have to be implemented in code, and unfortunately langflow does not have an intigration

still epoch
#

okay I see thanks Brody

#

Is there any other solution if you want to secure your railway instance with password protection?

ashen mason
#

a proxy with basicauth?
but does langflow not have a login page itself?

still epoch
#

no or at least if i use the template from their docs it does not - maybe from the docker, but how to set that up on railway

#

how do i use a proxy with basicauth

ashen mason
#

looks like you could probably just modify the langflow repo that railway cloned into your account and add an authentication middleware

still epoch
#

okay thanks, can you maybe point me at a tutorial or the name of a compatible authentication middleware?

ashen mason
#

I'm sorry I don't have any on hand, I've never used langflow myself

still epoch
#

okay i see, thank you

karmic sluice
#

send me the repo ill help u

#

theres no one-size-fits all tutorial thats the nice thing, you can pretty much use any oauth2 provider as login account

#

if u show me what ur repo runs on (apache servers or ngix whatever)

#

i can help u

#

@still epoch

karmic sluice
#

(0.5.0a1) is being developed with fleshing out authentication to production environments

#

it's in a dev branch right now which is downloadable

#

semi- unstable however

#

up until then

#

you could just go to the index.tsx file where ur main components are being rendered into reactDOM

#

(i usually use Nextjs for auth), but for react

#

u have the React Router

#

so you will wrap this page with your routed wrapper (LangFlowRouter) whatever u wanna call it

#

and you replace the main route of your App with the LangFlowRouter

#

which u just made

#

logging out u dont have to bother if ur the only user, just remove the token from ur browser

#

also CORS is really easy to setup

#

so your backend will ONLY take requests from your frontend domain

#

i can help you tomorrow as i need to go soon, but simply said,
1 make a firestore account and setup their oauth2,
2 setup an authentication endpoint with firestore (generate a json key in the firestore console), this is how u authenticate to ur firestore
3 either return a token like jwt or something different and cache/save the passwords with like salt hashers if u dont wanna use firestore, or bcrypt
4 download a simple tailwind css login page component, setup an ajax request with your form data to your firestore or backend (whatever u like)
5 create the react router like i mentioned earlier and wrap the langflow index page with the most important components in here (cors should take care of a lot arleady since react loads different than normal html etc so it will block out alot alrdy),

example (i hate js so mind my code but this should give you an idea)

// import react router and the redirect to serve your wrapper langflow index
import { Route, Redirect } from "react-router-dom";

// super basic login vars
function ProtectedRoute({ component: Component, ...rest }) {
  const token = localStorage.getItem('token');
  const isAuthenticated = token !== null;

// this is where you will wrap your components in from langflow
  return (
    <Route
      {...rest}
      render={props =>
// when the user is authed you will show the components (langflow)
        isAuthenticated ? (
          <Component {...props} />
        ) : (
          // route your login page from here
          <Redirect to="/login" />
        )
      }
    />
  );
}
#

index.tsx from langflow 0.5.0A1

import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import ContextWrapper from "./contexts";
import reportWebVitals from "./reportWebVitals";

import { ApiInterceptor } from "./controllers/API/api";
// @ts-ignore
import "./style/index.css";
// @ts-ignore
import "./style/applies.css";
// @ts-ignore
import "./style/classes.css";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <ContextWrapper>
    <BrowserRouter>
      <App />
      <ApiInterceptor />
    </BrowserRouter>
  </ContextWrapper>
);
reportWebVitals();

if you wrap it like i showed you above it would look something like this

import ReactDOM from "react-dom/client";
import { BrowserRouter, Route } from "react-router-dom";
import App from "./App";
// get a random TailWind CSS login page, any will do really it doesnt matter how it looks
import LoginPage from "./components/LoginPage";
import ProtectedRoute from "./components/ProtectedRoute";
import ContextWrapper from "./contexts";
import reportWebVitals from "./reportWebVitals";

import { ApiInterceptor } from "./controllers/API/api";
import "./style/index.css";
import "./style/applies.css";
import "./style/classes.css";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

// langflow components
root.render(
  <ContextWrapper>
    <BrowserRouter>
      <Route path="/login" component={LoginPage} />
      <ProtectedRoute path="/" component={App} />
      <ApiInterceptor />
    </BrowserRouter>
  </ContextWrapper>
);

reportWebVitals();
#

for the login page request, just declare 2 empty constants for the username and password wrapped in a function, and then send a post request using axios or whatever to your backend or firestore, the response will be your token that you will cache so you can stay authed

#
import React, { useState } from 'react';
import axios from 'axios';

function LangFlowLoginPage() {
  // define your empty strings
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
#

im trying to do it in very easy to understand blocks so you can follow it

#

if you need more help i can help u tomorrow

#

anyways so you have defined your credentials, now you just need to handle the submission and make your post request using axios

#
const handlesubmit = async (e) => {
  e.preventDefault();
// we use try in these scenarios to gracefully handle the responses (server could be offline etc or wrong credentials etc)
  try {
    // we define where we get our response from and where we save it in
    const response = await axios.post('https://YOUR_AUTHENTICATION_DOMAIN.COM/AUTH', {
      username: username,
      password: password
});
#

we now have the server telling us whether we have access yes or no so now we handle the response accordingly

ashen mason
#

quick question morpheus, are these ai code snippets?

karmic sluice
#
// so we are now calling the attributes of response and data, being the acces token
localStorage.setitem('token', response.data.accessToken);
window.location.href = '/'; 
// from here you send yourself FROM the login page TO the domain of your langflow
#

no haha

#

my js isnt amazing so big chance there will be some mistakes

#

so now hooking back to our route

#
// langflow components
root.render(
  <ContextWrapper>
    <BrowserRouter>
      <Route path="/login" component={LoginPage} />
      <ProtectedRoute path="/" component={App} />
      <ApiInterceptor />
    </BrowserRouter>
  </ContextWrapper>
);

reportWebVitals();
#

(i have no clue what reportWebVitals still holds as this comes straight from the langflow repo)

#

not that important if you are the only user, if ur on vercel and stuff with NextJS u probably seen the TimeTillFirstByte

#

thats what this tracks

#

no clue what the other ones do so u can probably leave as is

#

for CORS you can get an easy chrome extension

#

and lastly

#
src\frontend\src\pages

here are are the remaining pages, im not sure if they are accessable from the display domain

#
import { useContext, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { CardComponent } from "../../components/cardComponent";
import IconComponent from "../../components/genericIconComponent";
import Header from "../../components/headerComponent";
import { Button } from "../../components/ui/button";
import { USER_PROJECTS_HEADER } from "../../constants/constants";
import { TabsContext } from "../../contexts/tabsContext";
export default function HomePage() {
  const { flows, setTabId, downloadFlows, uploadFlows, addFlow, removeFlow } =
    useContext(TabsContext);

  // Set a null id
  useEffect(() => {
    setTabId("");
  }, []);
  const navigate = useNavigate();

  // Personal flows display
  return (
    <>
      <Header />
      <div className="main-page-panel">
        <div className="main-page-nav-arrangement">
          <span className="main-page-nav-title">
            <IconComponent name="Home" className="w-6" />
            {USER_PROJECTS_HEADER}
          </span>
          <div className="button-div-style">
            <Button
              variant="primary"
              onClick={() => {
                downloadFlows();
              }}
            >
              <IconComponent name="Download" className="main-page-nav-button" />
              Download Collection
            </Button>
            <Button
              variant="primary"
              onClick={() => {
                uploadFlows();
              }}
            >
              <IconComponent name="Upload" className="main-page-nav-button" />
              Upload Collection
            </Button>
            <Button
              variant="primary"
              onClick={() => {
                addFlow(null, true).then((id) => {
                  navigate("/flow/" + id);
                });
              }}
            >
              <IconComponent name="Plus" className="main-page-nav-button" />
              New Project
            </Button>
          </div>
        </div>
        <span className="main-page-description-text">
          Manage your personal projects. Download or upload your collection.
        </span>
        <div className="main-page-flows-display">
          {flows.map((flow, idx) => (
            <CardComponent
              key={idx}
              flow={flow}
              id={flow.id}
              button={
                <Link to={"/flow/" + flow.id}>
                  <Button
                    variant="outline"
                    size="sm"
                    className="whitespace-nowrap "
                  >
                    <IconComponent
                      name="ExternalLink"
                      className="main-page-nav-button"
                    />
                    Edit Flow
                  </Button>
                </Link>
              }
              onDelete={() => {
                removeFlow(flow.id);
              }}
            />
          ))}
        </div>
      </div>
    </>
  );
}
#

this is the most important one from langflow

#

the community page i'd ignore if i was you

#

it's no personal data bound to u on there

#

rest looks like js junk

#

so thats probably fine bro

#

i hope i explained it ok

ashen mason
#

im gonna be real with you, that was far too complex

karmic sluice
#

huh

#

nah bro i promise it looks way complexer than it is

#

read thru it for 10 min

#

follow all the comments i wrote

#

and u will understand

#

i coded alot with NextJs

#

and thats pretty much only components

#

they got rid of the React Router

#

but got the app router

#

which is way better

ashen mason
#

alright we will wait to hear back from op

karmic sluice
#

but this is still old react

#

i dont know how much u did with frontend brody

#

but react is basicly just the reject older brother of nextjs

#

it used to be good

#

but nextjs is SPEEEEED

#

and way securer with nextauth

ashen mason
#

they wanted to secure langflow

karmic sluice
#

they did in this dev branch

#

or like

#

partly

#

if this is too much

#

you can look into CloudFlare

#

i think they have these Zero Secority pages

#

something like that i havent really toyed around with themn

ashen mason
#

that doesnt secure langflow from the railway side of things though

karmic sluice
#

i mean

#

is the railway repo open for pull requests?

#

the fork

#

we could add this pretty easily

#

but the thing is, its an open source repo its so hard to 100% protect

#

if you really want to get in

#

u will

#

it has 5000 commits

#

its so hard to protect that

#

the SAFEST is to just run it on a VM somewhere and just RDP into that VM

#

or at home but thats alot of gpu power

ashen mason
#

they just wanted to put langflow behind a login page

karmic sluice
#

yea i mean for the railway devteam it would be pretty easy since they serve the data and domain

ashen mason
#

thats not something railway needs to do though

#

the user can do that

karmic sluice
#

that is true bro

#

what is langflow anyways compared to langchain

#

whats new

ashen mason
#

no clue

still epoch
#

first of all thank you, but this way too complicated 😄 - since you did all the work, would you mind just submitting it to the langflow repo, so that they can implement it?

karmic sluice
#

im not a contributor to the main langflow repo

#

its not alot of work

#

it just looks complex

#

tldr:
secure a few components with a wrapped authenticated route with firestore

still epoch
#

also i found out that it is maybe possible to enable user authetification in langflow by setting the enivornment variables for password and username

#

but the railway template doesn't allow to add variables before booting up

ashen mason
#

add them after

still epoch
#

would you maybe know how to deploy langflow with those two variables installed

#

i tried, but it doenst seem to do much

ashen mason
#

lets see what you tried

still epoch
karmic sluice
#

and then set the env variables

#

and it should automatically reboot

#

with them injected into ur deploy

ashen mason
#

unborn head?

karmic sluice
#

first deploy or commit

#

is an unborn head

ashen mason
#

dont call it that lmao

karmic sluice
#

github calls it that

ashen mason
#

yuck

still epoch
#

also where to mount the additional repo with this volume, so that langflow stays persistent?

karmic sluice
#

i havent worked with that repo

#

is it not just caching the data locally in the deploy

#

to a drive

#

or ?

still epoch
#

not sure

#

how to load is a docker file? that should work shouldn't it?

karmic sluice
#

yes railway will handle dockerfiles just fine

#

if thats what you mean

#

but you shouldnt have to deal with that really

still epoch
#

but i think if i load a docker file with a volume directly and the correct env files it could work

#

or i can use cli to check env variables

karmic sluice
#

u dont need env files

#

just define them in the 'Variables' tab of your deploy

#

however since you say it's been coded in already, langflow would be looking for 2 specific variable names

#

so you have to figure out what those are

#

maybe just PASSWORD and USERNAME

still epoch
#

i have them and i put them in the normal railway setup, but it doesn't work

karmic sluice
#

can you show me a screenshot of the variables tab?

still epoch
#

wait i am booting up a docker file

#

in the same instance

karmic sluice
#

alright bro

still epoch
#

interesting here i can also delete and add the domain name manually now

#

that way i could also use something like authorizer.dev or not?

karmic sluice
#

i mean technically your public domain will always be exposed, so if someone checked all railway url's programatically they would inevitably find your deployed langflow UI

#

so that's not really a safe option

still epoch
#

i see

karmic sluice
#

do you know by chance if the langflow UI is open source?

#

it's beautiful and i have need for something similair with these little connected nodes