惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
NISL@THU
NISL@THU
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
Schneier on Security
Schneier on Security
宝玉的分享
宝玉的分享
Cisco Talos Blog
Cisco Talos Blog
Help Net Security
Help Net Security
月光博客
月光博客
V
V2EX
量子位
T
Threat Research - Cisco Blogs
A
About on SuperTechFans
Google DeepMind News
Google DeepMind News
Google DeepMind News
Google DeepMind News
P
Privacy International News Feed
S
Secure Thoughts
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
A
Arctic Wolf
S
Schneier on Security
H
Hacker News: Front Page
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs
G
GRAHAM CLULEY
The Cloudflare Blog
博客园 - Franky
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
云风的 BLOG
云风的 BLOG
H
Heimdal Security Blog
The GitHub Blog
The GitHub Blog
C
Check Point Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
The Blog of Author Tim Ferriss
小众软件
小众软件
Hacker News: Ask HN
Hacker News: Ask HN
T
Tenable Blog
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
T
Troy Hunt's Blog
B
Blog
Blog — PlanetScale
Blog — PlanetScale
腾讯CDC

Vercel News

Vercel Open Source Program: Winter 2026 cohort How Notion Workers run untrusted code at scale with Vercel Sandbox How we run Vercel's CDN in front of Discourse From idea to secure checkout in minutes with Stripe Building Slack agents can be easy Scaling redirects to infinity on Vercel Advancing Python typing Gamma builds design-first agents with Vercel How Avalara turns pipe dreams into patent-pending with v0 Keeping community human while scaling with agents How OpenEvidence built a healthcare AI that physicians actually trust Security boundaries in agentic architectures Skills Night: 69,000+ ways agents are getting smarter Video Generation with AI Gateway We Ralph Wiggumed WebStreams to make them 10x faster How Stably ships AI testing agents in hours, not weeks How we built AEO tracking for coding agents Anyone can build agents, but it takes a platform to run them Introducing Geist Pixel The Vercel AI Accelerator is back with $6m in credits Making agent-friendly pages with content negotiation The Vercel OSS Bug Bounty program is now available Introducing the new v0 Run untrusted code with Vercel Sandbox, now generally available How Stripe built a game-changing app in a single flight with v0 How Sensay went from zero to product in six weeks AGENTS.md outperforms skills in our agent evals Agent skills explained: An FAQ Testing if "bash is all you need" AWS databases are now live on the Vercel Marketplace and v0 Use Perplexity Web Search with Vercel AI Gateway Introducing: React Best Practices Nick Bogaty joins Vercel as Chief Revenue Officer How Mux shipped durable video workflows with their @mux/ai SDK How to build agents with filesystems and bash How we made v0 an effective coding agent Stopping the slow death of internal tools Building AI-Generated Pixel Trading Cards with Vercel AI Gateway We removed 80% of our agent’s tools AI SDK 6 Our $1 million hacker challenge for React2Shell Cline now runs on Vercel AI Gateway How to prompt v0 Build smarter workflows with Notion and v0 Vercel launches partner certification Inside Workflow DevKit: How framework integrations work React2Shell Security Bulletin | Vercel Knowledge Base Billions of requests: Black Friday-Cyber Monday 2025 Investing in the Python ecosystem AWS Databases coming to the Vercel Marketplace How we built the v0 iOS app Workflow Builder: Build your own workflow automation platform Vercel Open Source Program: Fall 2025 cohort Self-driving infrastructure Vercel collaborates with Google for Gemini 3 Pro Preview launch Vercel: The anti-vendor-lock-in cloud How Nous Research used BotID to block automated abuse at scale How AI Gateway runs on Fluid compute What we learned building agents at Vercel Build and deploy data applications on Snowflake with v0 BotID Deep Analysis catches a sophisticated bot network in real-time Vercel achieves TISAX AL2 compliance to serve automotive partners Bun runtime on Vercel Functions David Totten Joins Vercel to Lead Global Field Engineering Vercel Ship AI 2025 recap You can just ship agents AI agents and services on the Vercel Marketplace Built-in durability: Introducing Workflow Development Kit Zero-config backends on Vercel AI Cloud Introducing Vercel Agent: Your new Vercel teammate Update regarding Vercel service disruption on October 20, 2025 Agents at work, a partnership with Salesforce and Slack Running Next.js in ChatGPT: How to Build ChatGPT Apps Talha Tariq joins Vercel as CTO of Security Just another (Black) Friday Server rendering benchmarks: Fluid Compute and Cloudflare Workers Towards the AI Cloud: Our Series F Collaborating with Anthropic on Claude Sonnet 4.5 to power intelligent coding agents Preventing the stampede: Request collapsing in the Vercel CDN BotID uncovers hidden SEO poisoning How we made global routing faster with Bloom filters What you need to know about vibe coding Scale to one: How Fluid solves cold starts Addressing security & quality issues with MCP tools - Vercel AI agents at scale: Rox’s Vercel-powered revenue operating system Agentic Infrastructure Zero Data Retention on AI Gateway Optimizing Vercel Sandbox snapshots How Waldium made a blog platform work for humans and AI alike How FLORA shipped a creative agent on Vercel's AI stack Agent responsibly Making Turborepo 96% faster with agents, sandboxes, and humans Unified reporting for all AI Gateway usage new.website joins forces with v0 SERHANT.'s playbook for rapid AI iteration Two startups at global scale without DevOps Chat SDK brings agents to your users 360 billion tokens, 3 million customers, 6 engineers Meet the 2026 Vercel AI Accelerator Cohort Build knowledge agents without embeddings
Securing data in your Next.js app with Okta and OpenFGA - Vercel – Vercel
Sam Bellen · 2024-05-16 · via Vercel News

7 min read

Modern Next.js applications can have large codebases operating across multiple environments, including client components running in the browser, Server Actions executing on the server, and more.

As applications become more complex, ensuring users can access only authorized data and actions becomes paramount. To that end, Next.js equips developers with tools to maintain data security. Developers can centralize authentication and authorization checks by integrating a Data Access Layer (DAL).

In this blog post, we'll introduce the concept of a DAL and use it to implement a fine-grained authorization model within a Next.js application.

Link to headingClient-side vs. server-side code in Next.js

Link to headingConfidential vs. public environments

Web applications typically run in two different environments: a confidential server environment and a public environment.

A confidential environment—your server—can execute code securely, store secrets, and should only expose data after running through all business logic.

The public environment is the browser. Interactive Next.js applications often have code that runs in the browser and reacts to events and updates that happen in or through the user interface. This client-side code is exposed in the browser and should never contain sensitive logic or secrets.

When these two environments interact with each other, the server should always double-check each action, as there has been too much wiggle room to do something unexpected from the browser.

Link to headingServer and client components

Modern Next.js codebases with the App Router offer the choice between client and server components for parts of the user interface or entire pages. Application logic can, for example, be executed exclusively on the server, and UI logic can live in a client component.

You can import the server-only package to mark a piece of code that will be run exclusively on the server. This will prevent the code from being executed in the client and potentially leak sensitive data like API keys or secrets.

Client components can be marked with 'use client', indicating to the underlying bundler (webpack or Turbopack) to enter into the client boundary.

Link to headingIntroducing a Data Access Layer into your application

As your applications grow, so do the number of touch points to fetch, update, or delete data from your database or other persistent storage solution.

The decisions about whether a user can access that data or perform those actions are often scattered throughout the codebase. A DAL can help keep a clear view of what data requests or mutations are happening and what checks are performed before they happen.

This Data Access Layer sits between your application logic and your persistent storage to ensure the requested data can be presented or changes to the data can be made. The DAL makes for the ideal location for these three types of actions:

  • Make sure the user has authenticated, so we know who they are

  • Check whether the authenticated user is authorized to request or change the data

  • Fetch the data from our database or perform updates on the data

We can add the checks with our authorization server(s) by expanding our flow chart above:

Link to headingAdding fine-grained authorization to our application

One of the most common approaches to authorization is role-based access control (RBAC), where a role contains a set of permissions and is assigned to each user.

RBAC is a simple way of determining what permissions a user has and what actions they should be able to perform within an application. More complex applications often require a more flexible approach to authorization, where access can be granted on a user and resource level instead of a general resource type.

Enter relationship-based access control, or ReBAC. Don’t let the one extra letter in the acronym fool you; it’s an entirely different approach to authorization.

Instead of checking a fixed set of permissions assigned to a user via roles, we look at the relationship between a user (or group of users) and a resource (or group of resources) to determine whether they should be able to see the data or perform an action on it.

Because we’re looking at the bigger picture and determining relationships between two entities, these relationships often don’t need to be explicitly defined. For example, if a user belongs to a group, it is enough to grant that group access, and all its members will automatically get access, too.

The same is true for a group of resources. If a user has access to, for example, a folder, they should automatically get access to all files within that folder without explicitly defining these relationships.

We’ll use OpenFGA, an open-source fine-grained authorization solution, to implement relationship-based access control in our application. If you prefer a managed SaaS version, you can use Okta FGA instead. It’s built on top of OpenFGA and uses the same authorization modeling language, engine, and SDKs.

Link to headingGetting started with OpenFGA

To start with OpenFGA, you need to create an authorization model that describes all resource types and their possible relationships. We’ll write the model using OpenFGA’s domain-specific language (DSL). A model for Google Drive might look something like this, where we describe a user, a file, and a folder resource type:

model

schema 1.1

type user

type file

relations

define can_delete: owner or owner from parent

define can_share: owner or owner from parent

define can_view: viewer or owner or viewer from parent

define can_write: owner or owner from parent

define is_owned: owner

define is_shared: can_view but not owner

define owner: [user]

define parent: [folder]

define viewer: [user, user:*]

type folder

relations

define can_create_file: owner or owner from parent

define can_create_folder: owner or owner from parent

define can_share: owner or owner from parent

define can_view: viewer or owner or viewer from parent

define owner: [user]

define parent: [folder]

define viewer: [user, user:*] or owner or viewer from parent

Next to the authorization model, the OpenFGA decision engine also needs some data to run against this model. This data is structured as tuples, which are sets of these three values:

  • A user is a resource consumer, like an application user or a folder

  • An object is our resource—a file, for example

  • A relation is the relationship between the user and the object, like owner or parent

We’ll explain how to add new tuples in the next section.

All that’s left to do is add the OpenFGA SDK to your codebase by running npm install @openfga/sdk. Once installed, you can use the SDK to create a new client that exposes all methods you’ll need to work with the OpenFGA decision engine in your codebase:

import { OpenFgaClient } from '@openfga/sdk';

const fgaClient = new OpenFgaClient({

// A link to your OpenFGA instance

apiUrl: process.env.FGA_API_URL,

// The ID of your store, the collection of tuples, on OpenFGA

storeId: process.env.FGA_STORE_ID,

// The ID of your Authorization model. This changes with each change to the

// model, and can be overwritten with each check

authorizationModelId: process.env.FGA_MODEL_ID,

});

Check out this blog post for more detailed information on how to start with OpenFGA in your Next.js application.

Now that you’ve got your model and data in place and the OpenFGA SDK installed, you can ask the OpenFGA decision engine to check any read or write operation your application performs. It will return a simple yes or no, indicating whether an action is permitted for the current user, resource, or situation.

Link to headingChecking FGA in our DAL

With our Data Access Layer, we can add an authorization check for each action. OpenFGA exposes a nice check method for performing an authorization check. Once the OpenFGA decision engine has considered all possible scenarios, it will let us know if we can proceed with the action or if we should abort and throw an error.

Here’s an example of what a getFile action in our Data Access Layer would look like. Notice that it does an authentication check first, then proceeds to check whether the authenticated user is authorized to view the requested file, and lastly fetches and returns the file from storage:

export async function getFile(fileId) {

try {

// Check if the user is authenticated

if (await !isAuthenticated()) {

return { error: "Unauthorized" };

}

// The user is authenticated so we can grab their ID

const userId = await getUserId();

// Check with OpenFGA if the user can view the file we're trying to fetch

const { allowed } = await openfgaClient.check({

user: `user:${userId}`,

relation: "can_view",

object: `file:${fileId}`,

});

// If the user is not authorized, we'll show an error

if (!allowed) {

return { error: "Forbidden" };

}

// The user was authorized, so we'll fetch our file and return it

return await getFileFromStore(fileId);

} catch (error) {

return { error };

}

}

When writing data, we’re also passing through our DAL so that a writeFile action would look very similar to the above.

Still, when updating data in a cloud storage application—like uploading a new file, for example—we must ensure our OpenFGA service knows about this new data. To do this, we’ll have to create new tuples: sets of data the decision engine considers when making a decision.

We’ll add two new tuples. The first marks the current user as the owner of the new file, and the second sets the current folder as the parent folder of a new file:

export async function uploadFile(parent, file) {

try {

// Check if the user is authenticated

if (await !isAuthenticated()) {

return { error: "Unauthorized" };

}

// The user is authenticated, so we can grab their ID

const userId = await getUserId();

// Check with OpenFGA if the user can create new files in the current location

const { allowed } = await openfgaClient.check({

user: `user:${userId}`,

relation: "can_create_file",

object: `folder:${parent}`,

});

// If the user is not authorized, we'll show an error

if (!allowed) {

return { error: "Forbidden" };

}

// Write the file to a persistent location

const {fileId} = await writeFile(file);

// Write OpenFGA tuples for the new file

await openfgaClient.writeTuples([

{

user: `user:${userId}`,

relation: "owner",

object: `file:${fileId}`,

},

{

user: `folder:${parent}`,

relation: "parent",

object: `file:${fileId}`,

},

]);

return file;

} catch (error) {

return { error };

}

}

Using a dedicated authorization service like OpenFGA, we have one centralized location where all authorization logic is created, maintained, and executed. This makes it easier to audit these decisions since you don’t need to go through your codebase and sift through endless if…else statements making these decisions.

On top of that, all your applications will have access to the same consistent authorization logic. When some of this logic changes, the applications don’t need changing because they’ll only ask yes/no questions to OpenFGA.

Link to headingError handling

You want your users to see as few errors as possible. Because of this, you may make optimistic decisions and follow a success-by-default approach, assuming all goes well unless an error occurs.

When dealing with user data, there is no room for such optimism. The best approach is to assume a user is not authenticated and authorized unless we determine they are.

In the two code samples, you’ll notice we start with our authentication check and immediately return an error if it fails, stopping the rest of the method's execution. The same is true for the authorization check. Only if both checks return the expected result do we touch the data.

Link to headingConclusion

Centralizing all data operations within a Data Access Layer (DAL) simplifies authentication and authorization checks, allowing you to build secure and scalable Next.js applications.

A fine-grained authorization approach, as with OpenFGA in the DAL, offers flexibility. It enables you to validate each action to ensure compliance with your authorization model. This ensures that unauthorized actions are quickly blocked, maintaining security and minimizing potential risks.