Authentication

Authenticating Calls

To authenticate API calls, the client must add the following header:

Authorization: Bearer TOKEN

where TOKEN is obtained by one of the methods below.

Token Types

There are three types of tokens which can have one of two access scopes.

Type Scope
Personal Access Token (PAT) personal Generated manually from the integrations page.
Doesn't expire, and can be revoked at any time.
Workspace Access Token (WAT) workspace Generated manually from the integrations page.
Doesn't expire, and can be revoked at any time.
OAuth Token personal,
workspace
Issued through the OAuth2 Flow.
Expires, must be refreshed.
Scope
personal Provides the same access level as the user who authorized the token.
workspace Provides FULL DATA ACCESS of the workspace.
Can be generated by workspace admins only.

NOTE: The workspace scope is not available on all plans.
Check https://grain.com/pricing to see if your plan includes Workspace API.

Tokens with the personal scope, including Personal Access Tokens, also authenticate the Grain MCP server at https://api.grain.com/_/mcp. Tokens with the workspace scope are not accepted by the MCP server.

OAuth2 Flow

This authentication method is for developers building integrations with Grain to be used by any Grain users.

The API supports a standard OAuth2 Authorization Code flow, including the PKCE extension for client-side only authentication. At least one redirect URI is required to register a new client. For browser-based client applications, a list of CORS origins can also be added.

Authorization Code

Step 1

Obtain the client_id and client_secret (only for server-side applications) credentials.

Step 2

Open the url https://grain.com/_/public-api/oauth2/authorize with the following query params.

Param
client_id Obtained separately in Step 1
redirect_uri Must exactly match a registered redirect URI. On localhost, 127.0.0.1 and [::1], any port matches
response_type Must be code
state Optional. Grain returns it unchanged in Step 4. PKCE already protects the flow, so state is only needed if your client relies on it
code_challenge A random string, hashed with SHA256 and base64 URL encoded
code_challenge_method Must be S256
scopes personal or workspace. Defaults to personal

Step 3

If the user is not already signed in to Grain, they will be prompted to sign in. After being authenticated, the user will be prompted to confirm the OAuth2 connection.

Step 4

The user will be redirected to redirect_uri from Step 2 with the code query param, and state if you sent one.

Step 5

Make a POST request to generate the token. See OAuth2 Generate Token

Diagram

sequenceDiagram
  participant you as You
  actor user as User
  participant grain as Grain
  
  Note right of you: Step 1
  you-->>grain: Request Client ID & Secret (manually)
  grain-->>you: Client ID & Secret

  Note right of you: Step 2
  user->>you: Requests OAuth
  you->>user: Open or Redirects to oauth2/authorize
  user->>grain: oauth2/authorize
  
  Note left of grain: Step 3
  grain->>user: Requests login
  user->>grain: Login
  
  grain->>user: Requests Confirm OAuth
  user->>grain: Confirms

	Note left of grain: Step 4  
  grain->>user: Redirects to redirect_uri w/code
  user->>you: redirect_uri w/code
  
  Note right of you: Step 5
  you->>grain: POST oauth2/token w/code
  grain->>you: access_token & refresh_token
  
  Note right of you: Refresh
  you->>grain: POST oauth2/token w/refresh_token
  grain->>you: access_token & refresh_token

Client ID Metadata Document

Public clients, such as MCP clients and native apps, can skip Step 1 by using an HTTPS URL as their client_id. That URL must serve a JSON Client ID Metadata Document describing the client.

{
  "client_id": "https://app.example.com/oauth/client.json",
  "client_name": "Example App",
  "redirect_uris": ["https://app.example.com/oauth/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
Field
client_id Required. Must exactly match the URL the document is served from
redirect_uris Required. The redirect_uri in Step 2 must exactly match one of these
client_name Shown to the user when they confirm the connection. Defaults to the URL's host
grant_types Must include authorization_code. Add refresh_token to receive refresh tokens
response_types Must be code if present
token_endpoint_auth_method Must be none if present. Client secrets are not supported

Grain applies these rules to documents and their clients:

  • The URL must use https and serve the document directly, with no redirects, in at most 5 KB.
  • Grain caches the document for the max-age in its Cache-Control header, between 5 minutes and 24 hours, and revalidates it with its ETag.
  • PKCE is required, so send code_challenge in Step 2 and code_verifier when generating the token.
  • http redirect URIs are only allowed on localhost, 127.0.0.1 and [::1], where any port matches.
  • The workspace scope is only available to clients verified by Grain.

Refresh Token

After the access_token has expired, you may generate a new one.

See OAuth2 Refresh Token