This is a JavaScript client library for the GoTrue API.
It lets you create and authenticate users and is a building block for constructing the UI for signups, password recovery, login and logout.
Play around the methods via the demo site.
yarn add gotrue-jsimport GoTrue from 'gotrue-js';
// Instantiate the GoTrue auth client with an optional configuration
auth = new GoTrue({
APIUrl: 'https://<your domain name>/.netlify/identity',
audience: '',
setCookie: false,
});APIUrl: The absolute path of the GoTrue endpoint. To find the APIUrl, go to your Netlify site dashboard and navigate to Project configuration > Identity. The URL will be https://<your-site>.netlify.app/.netlify/identity.
audience(optional): audience is one of the pre-defined JWT payload claims. It's an optional attribute which is set to be empty by default. If you were hosting your own identity service and wanted to support multitenancy, you would need audience to separate the users.
setCookie(optional): set to false by default. When set to true, the library sends an X-Use-Cookie header with requests, which tells the GoTrue server to set HttpOnly cookies containing the authentication tokens. This is more secure than localStorage alone because HttpOnly cookies cannot be accessed by JavaScript (protecting against XSS attacks).
Remember me: The login(), confirm(), and recover() methods accept an optional remember boolean parameter. When remember is true and setCookie is enabled, the server sets longer-lived session cookies. When false, the cookies expire when the browser session ends.
If an error occurs during the request, the promise may be rejected with an Error, HTTPError, TextHTTPError, or JSONHTTPError. These error classes are exported from the library and can be used for type checking:
import GoTrue, { HTTPError, JSONHTTPError, TextHTTPError } from 'gotrue-js';
auth.login(email, password).catch((error) => {
if (error instanceof JSONHTTPError) {
console.log('JSON error:', error.json);
} else if (error instanceof TextHTTPError) {
console.log('Text error:', error.data);
} else if (error instanceof HTTPError) {
console.log('HTTP error:', error.status);
}
});Create a new user with the specified email and password
auth.signup(email, password);Example usage:
auth
.signup(email, password)
.then((response) => console.log('Confirmation email sent', response))
.catch((error) => console.log("It's an error", error));Example response object:
{
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmation_sent_at": "2018-04-27T22:36:59.636416916Z",
"app_metadata": { "provider": "email" },
"user_metadata": null,
"created_at": "2018-04-27T22:36:59.632133283Z",
"updated_at": "2018-04-27T22:37:00.061039863Z"
}Also, make sure the Registration preferences under Identity settings in your Netlify dashboard are set to Open.
If the registration preferences is set to be Invite only, you'll get an error message like this:
{code: 403, msg: 'Signups not allowed for this instance'}
This function confirms a user sign up via a unique confirmation token
auth.confirm(token, remember);When a new user signed up, a confirmation email will be sent to the user if Autoconfirm isn't turned on under the identity settings.
In the email, there's a link that says "Confirm your email address".
When a user clicks on the link, it'll be redirected to the site with a fragment identifier #confirmation_token=Iyo9xHvsGVbW-9A9v4sDmQ in the URL.
For all good reasons, the confirmation_token is hidden from the browser via a redirect.
If you wish to manually confirm a user using the auth.confirm(token, remember) method,
you can copy the link location of the email and use the curl -I script to get the confirmation_token from your terminal. E.g.,
$ curl -I https://mandrillapp.com/track/click/30002868/example.netlify.com?p=example-token
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.12.2
Date: Tue, 15 May 2018 21:19:13 GMT
Content-Type: text/html; charset=utf-8
Set-Cookie: PHPSESSID=77c421bf85fa412e5f994f28a6b30956; expires=Wed, 16-May-2018 07:19:13 GMT; path=/; secure; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=77c421bf85fa412e5f994f28a6b30956; expires=Wed, 16-May-2018 07:19:13 GMT; path=/; secure; httponly
Location: https://example.netlify.com/#confirmation_token=Iyo9xHvsGVbW-9A9v4sDmQExample usage:
auth
.confirm(token, true)
.then((response) => {
console.log('Confirmation email sent', JSON.stringify({ response }));
})
.catch((error) => {
console.log(error);
});This method requires usage of browser window object localStorage. Test the usage in your front end code.
Example response object:
{
"response": {
"api": {
"apiURL": "https://example.netlify.com/.netlify/identity",
"_sameOrigin": true,
"defaultHeaders": {}
},
"url": "https://example.netlify.com/.netlify/identity",
"token": {
"access_token": "example-jwt-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "example-refresh_token",
"expires_at": 1526110512000
},
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-12T06:35:13Z",
"confirmation_sent_at": "2018-05-12T06:34:35Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-12T06:34:35Z",
"updated_at": "2018-05-12T06:34:35Z"
}
}Handles user login via the specified email and password
auth.login(email, password, remember)
Example usage:
auth
.login(email.value, password.value, true)
.then((response) => {
showMessage(`Success! Response: ${JSON.stringify({ response })}`, form);
})
.catch((error) => showMessage(`Failed :( ${JSON.stringify(error)}`, form));Example response object:
{
"response": {
"api": {
"apiURL": "https://example.netlify.com/.netlify/identity",
"_sameOrigin": true,
"defaultHeaders": {}
},
"url": "https://example.netlify.com/.netlify/identity",
"token": {
"access_token": "example-jwt-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "example-refresh_token",
"expires_at": 1526062471000
},
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-04T23:57:17Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-04T23:57:17Z",
"updated_at": "2018-05-04T23:57:17Z"
}
}This function sends a request to GoTrue API and triggers a password recovery email to the specified email address.
Similar to confirmation_token, the recovery_token is baked in the link of the email. You can also copy the link location from the email and run curl -I in the command line to grab the token.
auth.requestPasswordRecovery(email)
Example usage:
auth
.requestPasswordRecovery(email)
.then((response) => console.log('Recovery email sent', { response }))
.catch((error) => console.log('Error sending recovery mail: %o', error));Example response object:
{}
This function recovers a user account via a recovery token
auth.recover(recoveryToken, remember)
Example usage:
auth
.recover(token, true)
.then((response) => console.log('Logged in as %s', JSON.stringify({ response })))
.catch((error) => console.log('Failed to verify recover token: %o', error));Example response object:
{
"response": {
"api": {
"apiURL": "https://example.netlify.com/.netlify/identity",
"_sameOrigin": true,
"defaultHeaders": {}
},
"url": "https://example.netlify.com/.netlify/identity",
"token": {
"access_token": "example-jwt-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "example-refresh_token",
"expires_at": 1526107729000
},
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-12T05:48:49Z",
"invited_at": "2018-05-04T23:40:00Z",
"recovery_sent_at": "2018-05-12T05:48:13Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-04T23:40:00Z",
"updated_at": "2018-05-04T23:40:00Z"
}
}This function returns the current user object when a user is logged in. The user data is recovered from localStorage, so it may be stale if the user's profile was updated elsewhere.
auth.currentUser()
To fetch fresh user data from the server, call getUserData() on the user object:
const user = auth.currentUser();
if (user) {
await user.getUserData(); // Fetches and updates user data from server
}Example usage:
const user = auth.currentUser();Example response object:
{
"api": {
"apiURL": "https://example.netlify.com/.netlify/identity",
"_sameOrigin": true,
"defaultHeaders": {}
},
"url": "https://example.netlify.com/.netlify/identity",
"token": {
"access_token": "example-jwt-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "example-refresh_token",
"expires_at": 1525214326000
},
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-01T19:21:00Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-01T19:21:00Z",
"updated_at": "2018-05-01T19:21:00Z"
}This function updates a user object with specified attributes
user.update(attributes)
Users can update their user_metadata field. To do this, pass an object to the attributes.data key with the fields you want to update. Updates to a users app_metadata must be performed from a secure environment, such as a Lambda function. For examples on updating user and app metadata, see netlify/identity-update-user-data.
Example usage:
const user = auth.currentUser();
user
.update({ email: '[email protected]', password: 'password' })
.then((user) => console.log('Updated user %s', user))
.catch((error) => {
console.log('Failed to update user: %o', error);
throw error;
});Example response object:
{
"api": {
"apiURL": "https://example.netlify.com/.netlify/identity",
"_sameOrigin": true,
"defaultHeaders": {}
},
"url": "https://example.netlify.com/.netlify/identity",
"token": {
"access_token": "example-jwt-token",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "example-refresh_token",
"expires_at": 1525215471000
},
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-01T19:21:00Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-01T19:21:00Z",
"updated_at": "2018-05-01T22:04:07.923944421Z",
"new_email": "[email protected]",
"email_change_sent_at": "2018-05-01T22:04:07.49197052Z"
}This function retrieves a JWT token from a currently logged in user.
user.jwt(forceRefresh)
When to call .jwt(): Call this method before making authenticated API requests to your backend. The method automatically refreshes the token if it's expired (tokens expire after 1 hour by default), so you don't need to manually track expiration. Pass true to force a refresh even if the token hasn't expired.
Example usage:
const user = auth.currentUser();
const jwt = user.jwt();
jwt
.then((response) => console.log('This is a JWT token', response))
.catch((error) => {
console.log('Error fetching JWT token', error);
throw error;
});Example response object:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjUyMTk4MTYsInN1YiI6ImE5NG.98YDkB6B9JbBlDlqqef2nme2tkAnsi30QVys9aevdCw debugger eval code:1:43When a user logs in, they receive two tokens:
- Access token (
access_token): A short-lived JWT (1 hour by default) used to authenticate API requests - Refresh token (
refresh_token): A longer-lived token used to obtain new access tokens
The .jwt() method handles token refresh automatically:
- If the access token is still valid, it returns immediately
- If the access token has expired, it uses the refresh token to obtain a new one
- The new tokens are stored and the fresh access token is returned
You don't need to manually track expiration or refresh tokens — just call .jwt() before each authenticated request:
async function fetchProtectedData() {
const user = auth.currentUser();
const token = await user.jwt(); // Automatically refreshes if needed
return fetch('/api/protected', {
headers: { Authorization: `Bearer ${token}` },
});
}If the refresh token is invalid or expired (e.g., user was logged out on another device), the .jwt() call will fail and the session will be cleared.
This function removes the current session of the user and log out the user
user.logout()
Example usage:
const user = auth.currentUser();
user
.logout()
.then(response => console.log("User logged out");)
.catch(error => {
console.log("Failed to logout user: %o", error);
throw error;
});The following admin methods are currently not available to be used directly. You can access context.clientContext.identity and get a short lived admin token through a Lambda function and achieve the same goals, e.g., update user role, create or delete user etc. See Functions and Identity for more info.
For users of Netlify CLI - functions using admin methods will not work locally - they need to be deployed to your site in order to work as intended.
Let's create a simple login form in HTML and JavaScript to interact with a lambda function and test out the admin methods.
- Create an HTML form for user login
<h2>Log in</h2>
<form name="login">
<div class="message"></div>
<p>
<label>Email<br /><input type="email" name="email" required /></label>
</p>
<p>
<label>Password<br /><input type="password" name="password" required /></label>
</p>
<button type="submit">Log in</button>
</form>- Invoke lambda function. (In this example our function is names as
hello.js)
document.querySelector("form[name='login']").addEventListener("submit", e => {
e.preventDefault();
const form = e.target;
const { email, password } = form.elements;
auth
.login(email.value, password.value, true)
.then(response => {
const myAuthHeader = "Bearer " + response.token.access_token; //creates the bearer token
fetch("/.netlify/functions/hello", {
headers: { Authorization: myAuthHeader },
credentials: "include"
})
.then(response => {
console.log({ response });
})
.catch(error => {...});
})
.catch(error => {...});
});This function retrieves a user object with the specified user id
getUser(user) {
return this.user.\_request(`/admin/users/${user.id}`);
}Example usage:
import fetch from 'node-fetch';
exports.handler = async (event, context) => {
const { identity, user } = context.clientContext;
const userID = user.sub;
const userUrl = `${identity.url}/admin/users/{${userID}}`;
const adminAuthHeader = `Bearer ${identity.token}`;
try {
return fetch(userUrl, {
method: 'GET',
headers: { Authorization: adminAuthHeader },
})
.then((response) => response.json())
.then((data) => {
console.log('data', JSON.stringify(data));
return { statusCode: 204 };
})
.catch((error) => {
console.log('Failed to get user! 500! Internal.');
return {
statusCode: 500,
body: `Internal Server Error: ${error}`,
};
});
} catch (error) {
console.log('GOT HERE! 500! outer');
return { statusCode: 500, body: `Internal Server Error: ${error}` };
}
};Example response object:
{
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-09T06:28:46Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-09T06:28:46Z",
"updated_at": "2018-05-09T06:28:46Z"
}This function updates the an existing user with the specified attributes
updateUser(user, attributes = {}) {
return this.user._request(`/admin/users/${user.id}`, {
method: "PUT",
body: JSON.stringify(attributes)
});
}Example usage:
import fetch from "node-fetch";
exports.handler = async (event, context) => {
const { identity, user } = context.clientContext;
const userID = user.sub;
const userUrl = `${identity.url}/admin/users/${userID}`;
const adminAuthHeader = "Bearer " + identity.token;
try {
return fetch(userUrl, {
method: "PUT",
headers: { Authorization: adminAuthHeader },
body: JSON.stringify({ app_metadata: { roles: ["superstar"] } })
})
.then(response => {
return response.json();
})
.then(data => {
console.log("Updated a user! 204!");
console.log(JSON.stringify({ data }));
return { statusCode: 204 };
})
.catch(e => return {...});
} catch (e) { return e; }
};Example response object:
{
"data": {
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-09T06:52:58Z",
"app_metadata": {
"provider": "email",
"roles": ["superstar"]
},
"user_metadata": {},
"created_at": "2018-05-09T06:52:58Z",
"updated_at": "2018-05-11T00:26:27.668465915Z"
}
}To invite a user using the admin token, do a POST request to /invite endpoint. It's not possible to set user_metadata or app_metadata until a user has been created.
Example usage:
import fetch from 'node-fetch';
exports.handler = async (event, context) => {
const { identity } = context.clientContext;
const inviteUrl = `${identity.url}/invite`;
const adminAuthHeader = "Bearer " + identity.token;
try {
return fetch(inviteUrl, {
method: "POST",
headers: { Authorization: adminAuthHeader },
body: JSON.stringify({ email: "[email protected]" })
})
.then(response => {
return response.json();
})
.then(data => {
console.log("Invited a user! 204!");
console.log(JSON.stringify({ data }));
return { statusCode: 204 };
})
.catch(e => return {...});
} catch (e) { return e; };
};Example response:
{
"id": "example-id",
"aud": "",
"role": "",
"email": "[email protected]",
"invited_at": "2018-05-25T20:28:04.436230023Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": null,
"created_at": "2018-05-25T20:28:03.684905861Z",
"updated_at": "2018-05-25T20:28:04.862592451Z"
}This function creates a new user object with the specified new email and password and other optional attributes. User will not be confirmed unless confirm parameter is set to true.
createUser(email, password, attributes = {}) {
attributes.email = email;
attributes.password = password;
return this.user.\_request("/admin/users", {
method: "POST",
body: JSON.stringify(attributes)
});
}Example usage:
import fetch from "node-fetch";
exports.handler = async (event, context) => {
const { identity, user } = context.clientContext;
const userID = user.sub;
const usersUrl = `${identity.url}/admin/users`;
const adminAuthHeader = "Bearer " + identity.token;
try {
return fetch(usersUrl, {
method: "POST",
headers: { Authorization: adminAuthHeader },
body: JSON.stringify({ email: "[email protected]", password: "newpw", confirm: true })
})
.then(response => {
return response.json();
})
.then(data => {
console.log("Created a user! 204!");
console.log(JSON.stringify({ data }));
return { statusCode: 204 };
})
.catch(e => {...};
});
} catch (e) {
return e;
}
};Example response object:
{
"data": {
"id": "new-id",
"aud": "",
"role": "",
"email": "[email protected]",
"app_metadata": {
"provider": "email"
},
"user_metadata": null,
"created_at": "2018-05-11T00:37:34.475713996Z",
"updated_at": "2018-05-11T00:37:34.481743781Z"
}
}This function deletes an existing user object
deleteUser(user) {
return this.user.\_request(`/admin/users/${user.id}`, {
method: "DELETE"
});
}Example usage:
import fetch from 'node-fetch';
exports.handler = async (event, context) => {
const { identity, user } = context.clientContext;
const userID = user.sub;
const userUrl = `${identity.url}/admin/users/{${userID}}`;
const adminAuthHeader = `Bearer ${identity.token}`;
try {
return fetch(userUrl, {
method: 'DELETE',
headers: { Authorization: adminAuthHeader },
})
.then((response) => {
console.log('Deleted a user!');
return response.json();
})
.then((data) => {
console.log({ data });
return { statusCode: 204 };
})
.catch((error) => ({
statusCode: 500,
body: `Internal Server Error: ${error}`,
}));
} catch (error) {
return error;
}
};Example response object:
{ "data": {} }This function retrieves an array of user objects. The audience param is optional. It's for when you are hosting your own identity service and want to support multitenancy.
listUsers(aud) {
return this.user._request("/admin/users", {
method: "GET",
audience: aud
});
}Example usage:
import fetch from 'node-fetch';
exports.handler = async (event, context) => {
const { identity, user } = context.clientContext;
const usersUrl = `${identity.url}/admin/users`;
const adminAuthHeader = `Bearer ${identity.token}`;
try {
return fetch(usersUrl, {
method: 'GET',
headers: { Authorization: adminAuthHeader },
})
.then((response) => response.json())
.then((data) => {
console.log('data', JSON.stringify(data));
return { statusCode: 204 };
})
.catch((error) => ({
statusCode: 500,
body: `Internal Server Error: ${error}`,
}));
} catch (error) {
return error;
}
};Example response object:
{
"aud": "",
"users": [
{
"id": "example-id-01",
"aud": "",
"role": "",
"email": "[email protected]",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-09T18:14:51Z",
"updated_at": "2018-05-09T18:14:51Z"
},
{
"id": "example-id-02",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-09T06:52:58Z",
"app_metadata": {
"provider": "email"
},
"user_metadata": {},
"created_at": "2018-05-09T06:52:58Z",
"updated_at": "2018-05-09T06:52:58Z"
},
{
"id": "example-id-03",
"aud": "",
"role": "",
"email": "[email protected]",
"confirmed_at": "2018-05-09T06:28:46Z",
"app_metadata": {
"provider": "email",
"roles": ["admin"]
},
"user_metadata": {},
"created_at": "2018-05-09T06:28:46Z",
"updated_at": "2018-05-09T06:28:46Z"
}
]
}Currently we support Google, GitHub, GitLab, and BitBucket as directly supported in the Netlify app UI (other oauth providers require serverless functions to be set up correctly, but these don't.)
acceptInviteExternalUrl and loginExternalUrl are useful for that. You can see example usage in netlify-identity-widget

