In this guide, we explain how to create an authenticated AI application using LangChain and Morph. With Morph’s RBAC (Role-based Access Control) system, you can securely deploy an AI application built with LangChain within your organization.
Morph is a framework that allows you to build and deploy AI apps using Python and Markdown. In the tutorial, we will use the Morph cloud dashboard (available for free), so please log in to morph-data.io in advance.
LangChain is an excellent framework for developing applications that utilize large language models (LLMs). It comes equipped with a variety of components and third-party integrations.
In this article, we detail the steps to build an AI workflow with LangChain and deploy it as an authenticated AI application using Morph, ready for your team to use.
The outcome of this tutorial is available as the RBAC LangChain App in the following repository:
https://github.com/morph-data/morph-sample-apps
Environment Setup
Start a new project using the morph new command. It is recommended to choose poetry as the package manager.
morph new rbac-langchain-app In your pyproject.toml, set the dependencies as shown below:
[tool.poetry.dependencies] python = "<3.13,>=3.9" morph-data = "0.1.3" langchain = "0.3.16" langchain-core = "0.3.32" langchain-openai = "0.3.2" Since this tutorial uses the OpenAI API, be sure to set your API KEY in the .env file:
OPENAI_API_KEY=[Put your API KEY] Building the Frontend
With Morph, you can build your frontend by placing MDX files under the src/pages directory.
In this example, we use the component to create an interface where users can chat with the built AI. We also adjust the layout using the component and Tailwind CSS utility classes:
# Role-based access control with LangChain This example shows how to use LangChain with role-based access control (RBAC). <Grid cols={1} className="py-4"> <div className="p-4 bg-gray-50 rounded-lg shadow-sm border border-gray-200 hover:shadow-md transition-shadow"> <LLM postData="rbac_langchain" /> </div> </Grid> Now, run morph serve in your terminal and open http://localhost:8080 in your browser to see the interface.
Building the AI App with LangChain and Enforcing RBAC
We will build an AI workflow with LangChain that is accessible only to users with the ‘admin’ role.
From the MDX component, two parameters are automatically sent:
- prompt: The message entered by the user.
- thread_id: A unique ID that identifies the thread displayed in the Chat UI.
We use a global variable called history to store information about the most recent thread so that the system can respond to follow-up questions in context.
history = {} @morph.func def rbac_langchain(context: MorphGlobalContext): model = ChatOpenAI(model="gpt-4o-mini") # Initialize history when a new thread starts. if history.get("thread_id") != context.vars["thread_id"]: history["thread_id"] = context.vars["thread_id"] history["messages"] = [ SystemMessage(content="Please translate the following text from English to French."), ] # Append the user's prompt. history["messages"].append(HumanMessage(content=context.vars["prompt"])) result = "" for token in model.stream(history["messages"]): result += token.content yield create_chunk(token.content) history["messages"].append(AIMessage(content=result)) Next, we return an error message via chat if the user does not have the “admin” role:
# context.user_info comes from the user's authentication info. if "admin" not in context.user_info["roles"]: yield stream_chat("You are not authorized to use this feature.") return Complete Python Code
import morph from morph import MorphGlobalContext from morph_lib.stream import create_chunk from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, SystemMessage, AIMessage from morph_lib.stream import stream_chat history = {} @morph.func def rbac_langchain(context: MorphGlobalContext): # context.user_info comes from the user's authentication info. if "admin" not in context.user_info["roles"]: yield stream_chat("You are not authorized to use this feature. \\n\\n Please login as admin.") return model = ChatOpenAI(model="gpt-4o-mini") if history.get("thread_id") != context.vars["thread_id"]: history["thread_id"] = context.vars["thread_id"] history["messages"] = [ SystemMessage(content="Please translate the following text from English to French."), ] history["messages"].append(HumanMessage(content=context.vars["prompt"])) result = "" for token in model.stream(history["messages"]): result += token.content yield create_chunk(token.content) history["messages"].append(AIMessage(content=result)) Deploying and Sharing Your App
- Create a new project on the dashboard and issue an API Key.
- In your morph_project.yml, set the project_id you obtained from the project details page:
default_connection: DUCKDB package_manager: pip profile: default project_id: [Insert your project ID] result_cache_ttl: 0 source_paths: - src - Next, bind your API Key to the CLI:
morph config With everything set up, deploy your app from the dashboard!
morph deploy For more details, see: https://docs.morph-data.io/docs/ja/deploy/deploy
After the deployment is complete, click “Open” from the dashboard to access your app. You can verify that access control is working as expected based on the Project Role set under Member Access in the dashboard.


Top comments (0)