Introducing Nylas IAM

Introducing Nylas IAM

• 29 min read

Today we’re launching Nylas IAM. You can now control what each API key can do and where it can do it.

Three things this gives you:

  1. Every key carries permissions, so a job that reads mail has no way to send from the account.
  2. Every key carries a boundary, so it reaches one connected account, one workspace, one application, or your whole organization, and nothing outside it.
  3. Access Activity, so you can see every call a key made and every one we refused.

Your existing keys keep working exactly as they do today.

Say you have a job that reads customer replies and files them against the right record in your CRM. It never sends anything. Right now it holds your application key, which covers everything you’ve connected.

Here’s how to give it a key that reads messages in one workspace and stops there.

Every key comes from a principal

You give a principal the permissions a job needs and the one place it works in. Every key you issue from it gets both.

Permissions are what the key may do. Each part of the API has its own, like messages.read and calendars.create.

The resource is which accounts the key may touch. A principal binds to exactly one of four levels.

  • A connected account. One end user’s mailbox or calendar, which the API calls a grant.
  • A workspace. A group of connected accounts inside one application, grouped by something they share, like an email domain.
  • An application. Everything connected to that application.
  • Your organization. Every application under your account.

Pick the narrowest level that covers the job. The CRM job reads and never writes, so it needs messages.read and nothing else, and if it only runs against one customer’s accounts, it binds to that workspace. A search index that reads every account in one application binds at that application instead. One connected account is as narrow as it goes. A key bound to one mailbox reaches every folder and label in it.

Creating a principal and a key

Create a principal. Name it after the job that’ll hold the key, so you can tell your principals apart later. Pick the resource it works in, then give it the permissions that job needs, or start from one of the five roles that ship with IAM. Each permission is only valid at certain levels, and the list tells you which ones won’t do anything at the resource level you picked. 

Create a key from it. Every IAM key expires. Presets run from five years down to seven days, and five years is the default. You can set a custom date instead, up to ten years out. Copy the secret when it’s shown, because it’s stored only as a hash and you won’t see it again. It starts with nyk_v1_. Your existing keys start with nyk_v0_.

Swap the key. Replace the string in the CRM job’s config. Your SDK and request code don’t change.

curl https://api.us.nylas.com/v3/grants/GRANT_ID/messages \
  -H "Authorization: Bearer nyk_v1_YOUR_KEY"

What a refused call looks like

Before you build anything, you can watch one happen. Below is a mock inbox, and the switches are the permissions on the key that reads it. Turn off send, then try to send anyway.

This demo runs in a fully mocked environment. No emails are actually sent or received.

The call still goes out, comes back refused, and shows up in the log. Nothing in the app had to know the permission was missing.

A real refusal works the same way. A send from a read-only key comes back 403, and so does a read against an account the key's principal isn't bound to. We stop both at our own gateway, before the call reaches Google or Microsoft, and every refused call returns a request ID you can trace.

Why this matters most for agents

A support agent reads a customer's thread and drafts a suggested reply in your app for a human to approve. Its principal has messages.read on that customer's workspace.

Then the customer writes back: "just send it."

The agent has a finished draft and a customer asking for it. A person reading that thread would send the message, so the agent tries.

You can tell it not to in the system prompt, and most of the time that's enough. The principal has messages.read and nothing else, so the call comes back 403, the draft stays where it is, and the refusal shows up in Access Activity.

Nobody wrote a rule for "just send it." With a service you built, you already know every call it makes, so a scoped key mostly confirms what the code does. An agent decides at runtime, and you can't list those decisions ahead of time. The key catches the ones you never thought of.

Answering a security review

Someone asks what the CRM job can reach. The answer is on its principal page and it fits on one line: reads messages, one workspace. Anyone can read that off the dashboard without opening the source.

When they ask what it actually did, that's Access Activity. It records every call, the key that made it, the account it touched, and the outcome. Filter by one key and you'll see every call it made, including the ones we refused. We write that record at the point where we check the request, so it looks the same whichever provider the account is on.

Information internationally masked for display, real usage includes access to all masked data.

There's a second view for configuration changes. We write each record in the same transaction as the change it describes, and we keep configuration change records for 400 days.

Common use cases

Multi-tenant platforms. You run a platform for fifty companies, each with its own connected mailboxes. Every tenant gets its own principal bound to its own workspace. If your code passes the wrong tenant's account, the call is refused at our end before it reaches the mailbox. Your tenant boundary stops depending on every line of your code being right.

Regulated industries. Your customer is a hospital, and their security team asks which of your services read a particular mailbox. Filter Access Activity by that account and you have every call your integration made with a Nylas key, including the ones we refused. Answering that used to mean reading your own code and hoping you'd covered everything.

Enterprise buyers. A prospect's security reviewer wants to know what your integration can reach before they'll sign. Its principal page lists the permissions and the one workspace it's bound to. The review stops being something you schedule a call for.

Migrating your existing keys

Your existing application key keeps working while you migrate, so move one job at a time. A principal can hold up to ten keys at once, so you can deploy a replacement before you remove the old one.

Shutting a key off is a different thing from scoping it. If you disable a key, its next call returns 401. If you delete it, the string stops working permanently. The record itself stays, so its entries in Access Activity still point at something. Neither one needs a redeploy.

We're not deprecating application keys. Nothing changes at Google or Microsoft either, so your users keep their existing connections.

IAM is included on every plan, and you set it all up in your Nylas dashboard.

Get started today

Start with the job you'd least like to explain. Make it a principal, give it the one permission it needs, bind it to the narrowest resource that covers its work, and swap the key in its config. Next time someone asks what it can reach, you can read them the principal.

Related resources

Best meeting transcription tools for developers in 2026

Getting accurate meeting transcripts to power features and workflows in your SaaS application can take…

Best AI agent email providers for developers in 2026

AI agents are starting to communicate the way people do. They schedule meetings, coordinate projects,…

Best meeting bot APIs for developers in 2026

Meetings are where product decisions get made, deals close, candidates get evaluated, and patients get…