Only show these results:

Create grants with OAuth and an API key

Most projects that used Hosted authentication in Nylas v2.x should use the new OAuth method to get authorization from end users, along with your Nylas application's API key. This is the recommended authentication method, and the easiest way to integrate with Nylas.

API keys are new in Nylas v3. They are generated in the v3 Dashboard, and are specific to each Nylas application. You can set the default expiration time separately for each key, and revoke them from the v3 Dashboard.

In Nylas v3, you use the familiar Hosted OAuth flow to get the end user's authorization for scopes and create their grant ID. Then, you use your application-specific API key to access their data and make other requests. This allows you to use the same request method for everything in your application, including endpoints that don't specify a grant (for example, webhooks and some group calendar features).

Before you begin

Before you begin, make sure you set up all the required parts for your authentication system:

  1. If you haven't already, log in to the v3 Dashboard and create a Nylas application.
  2. Generate an API key for your application in the v3 Dashboard.
  3. Create a provider auth app in the provider's console or application. See the detailed instructions for creating a Google or Azure provider auth app.
  4. Create a connector for the provider you want to authenticate with.
  5. Add your project's callback URIs ("redirect URIs") in the Nylas Dashboard.

Creating grants with OAuth and API Key

📝 Note: Because Nylas uses the schema outlined in RFC 9068 to ensure that it is compatible with all OAuth libraries in all languages, the format for the /tokeninfo endpoint is different from the other OAuth endpoints.

The rough OAuth process is...

  1. The end user clicks a link or button in your app to start an OAuth request.
  2. Nylas forwards the end user to their auth provider where they complete the OAuth flow, either accepting or declining the requested scopes.
  3. The auth provider directs the end user back to the Nylas callback URI, and includes URL parameters that indicate success or failure, and other information.
  4. If auth was successful, Nylas creates an unverified grant record, then forwards the user to your application's callback_uri and includes the access code from the provider in the URL as a parameter.
  5. Your application uses the code to perform a token exchange with the provider.
  6. When the token exchange completes successfully, Nylas marks the grant record as verified and sends the grant_id to you.

At this point, instead of using doing a token exchange to get an access token for the specific user, you can use an API key you created to access the Nylas APIs. Your app can use that grant_id to specify which data to access on behalf of the user.

Start an authorization request

The first step of the authentication process is to start an authorization request. Usually this is a button or link that the end user clicks.

Your project redirects the end user to the authorization request endpoint (GET api.us.nylas.com/v3/connect/auth) and includes their information as query parameters, as in the example below. When the user goes to this URL, Nylas starts a secure authentication session and redirects them to the authentication provider website.

/v3/connect/auth?
client_id=<NYLAS_CLIENT_ID>
&redirect_uri=https://myapp.com/callback-handler // Your application callback_uri.
&response_type=code
&access_type=online
&provider=google // (Optional) Provider
&state=sQ6vFQN // (Optional) OAuth context

This cURL request uses access_type=online to specify not to send a refresh token. This is technically optional, but we've included it in the example because we're using the API key method and don't want a refresh token.

There are several other optional items you can choose to pass:

  • provider indicates which connector your Nylas application should use. If you only have one connector you can omit this parameter. If you have more than one connector, you can either specify which one to use, or omit this and Nylas gives the user a list of connectors to choose from when they start the auth process.
  • scopes are optional if you set default scopes on the connector. Scopes set from this request override the default connector scopes.

You can also start an authorization request using the Nylas SDKs, as in the examples below.

import 'dotenv/config'
import express from 'express'
import Nylas from 'nylas'

const config = {
clientId: process.env.NYLAS_CLIENT_ID,
callbackUri: "http://localhost:3000/oauth/exchange",
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI
}

const nylas = new Nylas({
apiKey: config.apiKey,
apiUri: config.apiUri
})

const app = express()
const port = 3000

// Route to initialize authentication
app.get('/nylas/auth', (req, res) => {
const authUrl = nylas.auth.urlForOAuth2({
clientId: config.clientId,
provider: 'google',
redirectUri: config.callbackUri,
loginHint: 'email_to_connect',
})

res.redirect(authUrl)
})
from dotenv import load_dotenv
load_dotenv()

import json
import os
from functools import wraps
from io import BytesIO
from flask import Flask, request, redirect
from nylas import Client

nylas = Client(
os.environ.get("NYLAS_CLIENT_ID"),
os.environ.get("NYLAS_API_URI")
)

REDIRECT_CLIENT_URI = 'http://localhost:9000/oauth/exchange'
flask_app = Flask(__name__)

CORS(flask_app, supports_credentials=True)
@flask_app.route("/nylas/generate-auth-url", methods=["GET"])

def build_auth_url():
auth_url = nylas.auth.url_for_oauth2(
config={
"client_id": os.environ.get("NYLAS_CLIENT_ID"),
"provider": 'google',
"redirect_uri": REDIRECT_CLIENT_URI,
"login_hint": "email_to_connect"
}
)

return redirect(auth_url)
require 'nylas'
require 'sinatra'

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")

get '/nylas/auth' do
config = {
client_id: "<API_CLIENT>",
provider: "google",
redirect_uri: "http://localhost:4567/oauth/exchange",
login_hint: "<email_to_connect>"
}

url = nylas.auth.url_for_oauth2(config)

redirect url
end
import java.util.*;
import static spark.Spark.*;
import com.nylas.NylasClient;
import com.nylas.models.*;

public class AuthRequest {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

get("/nylas/auth", (request, response) -> {
List<String> scope = new ArrayList<>();
scope.add("https://www.googleapis.com/auth/userinfo.email");

UrlForAuthenticationConfig config = new UrlForAuthenticationConfig(
"<API_CLIENT>",
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.GOOGLE,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"<email_to_connect>"
);

String url = nylas.auth().urlForOAuth2(config);

response.redirect(url);

return null;
});
}
}
import com.nylas.NylasClient
import com.nylas.models.AccessType
import com.nylas.models.AuthProvider
import com.nylas.models.Prompt
import com.nylas.models.UrlForAuthenticationConfig
import spark.kotlin.Http
import spark.kotlin.ignite

fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val http: Http = ignite()

http.get("/nylas/auth") {
val scope = listOf("https://www.googleapis.com/auth/userinfo.email")

val config : UrlForAuthenticationConfig = UrlForAuthenticationConfig(
"<API_CLIENT>",
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.GOOGLE,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"<email_to_connect>"
)

val url = nylas.auth().urlForOAuth2(config)

response.redirect(url)
}
}

Authorization response and grant creation

Each provider displays the consent and approval steps differently, and it's visible only to the end user. In all cases the user authenticates, and either accepts or declines the scopes your project requested.

🔍 If an end user authenticates using their Google account, they might be directed to Google's authorization screen twice. This is a normal part of Nylas' Hosted auth flow, and ensures that all necessary scopes are approved during the auth process.

Next, the auth provider sends the user to the Nylas redirect_uri (https://api.us.nylas.com/v3/connect/callback). Nylas uses the information in the response to find your Nylas application by client_id and, if the auth was successful, create an unverified grant record for the user and record their details.

Get the user's code

Nylas uses your Nylas application's callback_uri (for example, app.example.com/callback-handler) to forward the user back to your project. Nylas includes the code it got from the auth provider as a query parameter, as in the example below.

https://myapp.com/callback-handler?
code=R2E_t1Mf88lipCSqrKvWZhKKzpMVXb0UOuct-U5LidwJud5vMjH1I4q...
&state=... // If you included a state in the initial auth request, it's returned here.

Token exchange and grant verified

Next you use the /v3/connect/token endpoint to exchange the code for an access token, as in the example below. The authentication provider responds with an access token and other information.

POST /token HTTP/1.1
Host: /v3/connect/token
Content-Type: application/json

{
"code": "<code>",
"client_id": "<NYLAS_CLIENT_ID>",
"redirect_uri": "<APPLICATION_REDIRECT_URI>", // Your application callback_uri.
"grant_type": "authorization_code"
}
{
"access_token": "<ACCESS_TOKEN>",
"token_type": "Bearer",
"id_token": "<id_token>",
"grant_id": "<grant_id>"
}

You can also exchange the code using the Nylas SDKs, as in the following examples.

app.get('/oauth/exchange', async (req, res) => {
const code = req.query.code

if (!code) {
res.status(400).send('No authorization code returned from Nylas')

return
}

try {
const response = await nylas.auth.exchangeCodeForToken({
clientId: config.clientId,
redirectUri: config.redirectUri,
code
})

const { grantId } = response

res.status(200)
} catch (error) {
res.status(500).send('Failed to exchange authorization code for token')
}
})
@flask_app.route("/oauth/exchange", methods=["GET"])

def exchange_code_for_token():
code_exchange_response = nylas.auth.exchange_code_for_token(
request={
"code": request.args.get('code'),
"client_id": os.environ.get("NYLAS_CLIENT_ID"),
"redirect_uri": REDIRECT_CLIENT_URI
}
)

return {
'grant_id': code_exchange_response.grant_id
}
get '/oauth/exchange' do
code = params[:code]
status 404 if code.nil?

begin
response = nylas.auth.exchange_code_for_token({
client_id: '<NYLAS_CLIENT_ID>',
redirect_uri: 'http://localhost:4567/oauth/exchange',
code: code
})
rescue StandardError
status 500
else
responde_data = response[:grant_id]
"#{response_data}"
end
end
get("/oauth/exchange", (request, response) -> {
String code = request.queryParams("code");

if(code == null) { response.status(401);}
assert code != null;

CodeExchangeRequest codeRequest = new CodeExchangeRequest(
"http://localhost:4567/oauth/exchange",
code,
"<NYLAS_CLIENT_ID>",
"nylas"
);

try {
CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);

return "%s".formatted(codeResponse);
} catch(Exception e) {
return "%s".formatted(e);
}
});
http.get("/oauth/exchange") {
val code : String = request.queryParams("code")

if(code == "") { response.status(401) }

val codeRequest : CodeExchangeRequest = CodeExchangeRequest(
"http://localhost:4567/oauth/exchange",
code,
"<NYLAS_CLIENT_ID>",
"nylas"
)

try {
val codeResponse : CodeExchangeResponse = nylas.auth().exchangeCodeForToken(codeRequest)

codeResponse
} catch (e : Exception) {
e
}
}

When this is successfully completed, Nylas marks the end user's grant as verified and sends you their grant_id and email address.

Record the grant ID and use your API Key

As long as authentication succeeded, you can stop the OAuth process here, record the grant_id created for the end user, and continue using your API key to make requests on behalf of this grant, as in the following examples.

You don't need to record the user's OAuth access token, or any other OAuth information. Nylas stores what it needs in the end user's grant record.

curl --request POST \
--url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=<NYLAS_CALENDAR_ID> \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"title": "Birthday Party",
"status": "confirmed",
"busy": true,
"participants": [{
"name": "Aristotle",
"email": "[email protected]",
"status": "yes"
}],
"description": "Come ready to skate",
"when": { "time": 1408875644 },
"location": "Roller Rink",
"recurrence": [
"RRULE:FREQ=WEEKLY;BYDAY=MO",
"EXDATE:20211011T000000Z"
]
}'
import 'dotenv/config'
import Nylas from 'nylas'

const config = {
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(config)
const identifier = process.env.NYLAS_GRANT_ID

async function getGrantInformation() {
try {
const account = await nylas.auth.grants.find({ identifier });

console.log('Account Information:', account);
} catch (error) {
console.error('Error retrieving account information:', error);
}
}

getGrantInformation();
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
account = nylas.grants.find(grant_id)

print(account)
require 'nylas'

nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")
query_params = {calendar_id: "<NYLAS_GRANT_ID>"}
events, _request_ids = nylas.events.list(identifier: "<NYLAS_CALENDAR_ID>", query_params: query_params)

events.each {|event|
puts "#{event[:id]} | #{event[:title]}"
}
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.List;

public class read_calendar_events {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
ListEventQueryParams query_params = new ListEventQueryParams.Builder("<NYLAS_GRANT_ID>").build();
List<Event> events = nylas.events().list("<NYLAS_CALENDAR_ID>", query_params).getData();

for(Event event : events){
System.out.printf(" %s | %s%n", event.getId(), event.getTitle());
}
}
}
import com.nylas.NylasClient
import com.nylas.models.ListEventQueryParams

fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
var queryParams = ListEventQueryParams.Builder("<NYLAS_CALENDAR_ID>").build()
var events = nylas.events().list("<NYLAS_GRANT_ID>", queryParams).data

for(event in events){
println(event.id + " | " + event.title)
}
}