Accounts
Accounts-base
The Meteor Accounts system builds on top of the userId
support in publish
and methods
. The core packages add the concept of user documents stored in the database, and additional packages add secure password authentication, integration with third party login services, and a pre-built userinterface.
The basic Accounts system is in the accounts-base
package, but applications typically include this automatically by adding one of the login provider packages: accounts-password
, accounts-facebook
, accounts-github
, accounts-google
, accounts-meetup
, accounts-twitter
, or accounts-weibo
.
Read more about customizing user accounts in the Accounts article in the Meteor Guide.
Accounts with Session Storage
By default, Meteor uses Local Storage to store, among other things, login tokens in your browser session. But, for some applications, it makes sense to use Session Storage instead. You can achieve this by adding this to your settings:
{
// ... all other settings,
"public": {
// ... all your public settings
"packages": {
"accounts": {
"clientStorage": "session"
}
}
}
}
Meteor.user
Summary:
Get the current user record, or null
if no user is logged in. A reactive data source.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | No |
Retrieves the user record for the current user from the Meteor.users
collection.
On the client, the available fields will be those that are published from the server (other fields won't be available on the client). By default the server publishes username
, emails
, and profile
(writable by user). See Meteor.users
for more on the fields used in user documents.
On the server, this will fetch the record from the database. To improve the latency of a method that uses the user document multiple times, save the returned record to a variable instead of re-calling Meteor.user()
.
Fetching the full user document can cause unnecessary database usage on the server and over-reactivity on the client, particularly if you store lots of custom data on it. Therefore it is recommended to use the options
parameter to only fetch the fields you need:
import { Meteor } from "meteor/meteor";
const userName = Meteor.user({ fields: { "profile.name": 1 } }).profile.name;
Meteor.userAsync
Summary:
Get the current user record, or null
if no user is logged in. A reactive data source.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | No |
Same as Meteor.user
, but returns a promise and is available on the server.
import { Meteor } from "meteor/meteor";
const user = await Meteor.userAsync();
Meteor.userId
Summary:
Get the current user id, or null
if no user is logged in. A reactive data source.
import { Meteor } from "meteor/meteor";
Meteor.userId();
This collection contains one document per registered user. Here's an example user document:
{
_id: 'QwkSmTCZiw5KDx3L6', // Meteor.userId()
username: 'cool_kid_13', // Unique name
emails: [
// Each email address can only belong to one user.
{ address: 'cool@example.com', verified: true },
{ address: 'another@different.com', verified: false }
],
createdAt: new Date('Wed Aug 21 2013 15:16:52 GMT-0700 (PDT)'),
profile: {
// The profile is writable by the user by default.
name: 'Joe Schmoe'
},
services: {
facebook: {
id: '709050', // Facebook ID
accessToken: 'AAACCgdX7G2...AbV9AZDZD'
},
resume: {
loginTokens: [
{ token: '97e8c205-c7e4-47c9-9bea-8e2ccc0694cd',
when: 1349761684048 }
]
}
}
}
A user document can contain any data you want to store about a user. Meteor treats the following fields specially:
username
: a unique String identifying the user.emails
: an Array of Objects with keysaddress
andverified
; an email address may belong to at most one user.verified
is a Boolean which is true if the user has verified the address with a token sent over email.createdAt
: the Date at which the user document was created.profile
: an Object which the user can create and update with any data. Do not store anything onprofile
that you wouldn't want the user to edit unless you have a deny rule on theMeteor.users
collection.services
: an Object containing data used by particular login services. For example, itsreset
field contains tokens used by forgot password links, and itsresume
field contains tokens used to keep you logged in between sessions.
Like all Mongo.Collections, you can access all documents on the server, but only those specifically published by the server are available on the client. You can also use all Collection methods, for instance Meteor.users.remove
on the server to delete a user.
By default, the current user's username
, emails
and profile
are published to the client. You can publish additional fields for the current user with:
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find(
{ _id: this.userId },
{
fields: { other: 1, things: 1 },
}
);
} else {
this.ready();
}
});
Meteor.subscribe("userData");
If the autopublish package is installed, information about all users on the system is published to all clients. This includes username
, profile
, and any fields in services
that are meant to be public (eg services.facebook.id
, services.twitter.screenName
). Additionally, when using autopublish more information is published for the currently logged in user, including access tokens. This allows making API calls directly from the client for services that allow this.
Users are by default allowed to specify their own profile
field with Accounts.createUser
and modify it with Meteor.users.update
. To allow users to edit additional fields, use Meteor.users.allow
. To forbid users from making any modifications to their user document:
import { Meteor } from "meteor/meteor";
Meteor.users.deny({ update: () => true });
Meteor.loggingIn Client only
Client only
Summary:
True if a login method (such as Meteor.loginWithPassword
,
Meteor.loginWithFacebook
, or Accounts.createUser
) is currently in
progress. A reactive data source.
import { Meteor } from "meteor/meteor";
Meteor.loggingIn();
For example, the accounts-ui
package uses this to display an animation while the login request is being processed.
Meteor.loggingOut Client only
Client only
Summary:
True if a logout method (such as Meteor.logout
) is currently in
progress. A reactive data source.
import { Meteor } from "meteor/meteor";
Meteor.loggingOut();
Meteor.logout Client only
Client only
Summary:
Log the user out.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Meteor } from "meteor/meteor";
Meteor.logout(
() => {}
);
Meteor.logoutOtherClients Client only
Client only
Summary:
Log out other clients logged in as the current user, but does not log out the client that calls this function.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Meteor } from "meteor/meteor";
Meteor.logoutOtherClients(
() => {}
);
For example, when called in a user's browser, connections in that browser remain logged in, but any other browsers or DDP clients logged in as that user will be logged out.
Meteor.loginWithPassword Client only
Client only
Summary:
Log the user in with a password.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
selector | Object or String | Either a string interpreted as a username or an email; or an object with a
single key: | Yes |
password | String | The user's password. | Yes |
callback | function | Optional callback.
Called with no arguments on success, or with a single | No |
import { Meteor } from "meteor/meteor";
Meteor.loginWithPassword(
selector,
"password",
() => {}, // this param is optional
);
If there are multiple users with a username or email only differing in case, a case sensitive match is required. Although createUser
won't let you create users with ambiguous usernames or emails, this could happen with existing databases or if you modify the users collection directly.
This method can fail throwing one of the following errors:
- "Unrecognized options for login request [400]" if
user
orpassword
is undefined. - "Match failed [400]" if
user
isn't an Object or String, orpassword
isn't a String. - "User not found [403]" if the email or username provided in
user
doesn't belong to a registered user. - "Incorrect password [403]" if the password provided is incorrect.
- "User has no password set [403]" if
user
doesn't have a password.
This function is provided by the accounts-password
package. See the Passwords section below.
Meteor.loginWith<ExternalService> Client only
Client only
Summary:
Log the user in using an external service.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | No | |
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Meteor } from "meteor/meteor";
Meteor.loginWith<ExternalService>(
options, // this param is optional
() => {}, // this param is optional
);
Available functions are:
Meteor.loginWithMeteorDeveloperAccount
Meteor.loginWithFacebook
options
may also include Facebook'sauth_type
parameter
Meteor.loginWithGithub
Meteor.loginWithGoogle
options
may also include Google's additional URI parameters
Meteor.loginWithMeetup
Meteor.loginWithTwitter
options
may also include Twitter'sforce_login
parameter
Meteor.loginWithWeibo
These functions initiate the login process with an external service (eg: Facebook, Google, etc), using OAuth. When called they open a new pop-up window that loads the provider's login page. Once the user has logged in with the provider, the pop-up window is closed and the Meteor client logs in to the Meteor server with the information provided by the external service.
Requesting Permissions
In addition to identifying the user to your application, some services have APIs that allow you to take action on behalf of the user. To request specific permissions from the user, pass the requestPermissions
option the login function. This will cause the user to be presented with an additional page in the pop-up dialog to permit access to their data. The user's accessToken
— with permissions to access the service's API — is stored in the services
field of the user document. The supported values for requestPermissions
differ for each login service and are documented on their respective developer sites:
- Facebook: http://developers.facebook.com/docs/authentication/permissions/
- GitHub: http://developer.github.com/v3/oauth/#scopes
- Google: https://developers.google.com/identity/protocols/googlescopes
- Meetup: http://www.meetup.com/meetup_api/auth/#oauth2-scopes
- Twitter, Weibo, Meteor developer accounts:
requestPermissions
currently not supported
External login services typically require registering and configuring your application before use. The easiest way to do this is with the accounts-ui
package which presents a step-by-step guide to configuring each service. However, the data can be also be entered manually in the ServiceConfiguration.configurations
collection, which is exported by the service-configuration
package.
Configuring Services
First, add the service configuration package:
meteor add service-configuration
Then, inside the server of your app (this example is for the Weebo service), import ServiceConfiguration
:
import { ServiceConfiguration } from "meteor/service-configuration";
ServiceConfiguration.configurations.upsert(
{ service: "weibo" },
{
$set: {
loginStyle: "popup",
clientId: "1292962797", // See table below for correct property name!
secret: "75a730b58f5691de5522789070c319bc",
},
}
);
Since Meteor 2.7 you no longer need to manually set the configuration and instead can use Meteor settings by setting your services under Meteor.settings.packages.service-configuration.<service>
. All the properties can be set under the service and will be added to the database as is, so make sure that they are correct. For the example above, the settings would look like:
{
"packages": {
"service-configuration": {
"weibo": {
"loginStyle": "popup",
"clientId": "1292962797",
"secret": "75a730b58f5691de5522789070c319bc"
}
}
}
}
The correct property name to use for the API identifier (i.e. clientId
in the above example) depends on the login service being used, so be sure to use the correct one:
Property Name | Services |
---|---|
appId | |
clientId | Github, Google, Meetup, Meteor Developer Accounts, Weibo |
consumerKey |
Additionally, each external service has its own login provider package and login function. For example, to support GitHub login, run the following in your terminal:
meteor add accounts-github
and use the Meteor.loginWithGithub
function:
import { Meteor } from "meteor/meteor";
Meteor.loginWithGithub(
{
requestPermissions: ["user", "public_repo"],
},
(error) => {
if (error) {
Session.set("errorMessage", error.reason || "Unknown error");
}
}
);
Login service configuration is sent from the server to the client over DDP when your app starts up; you may not call the login function until the configuration is loaded. The function Accounts.loginServicesConfigured()
is a reactive data source that will return true once the login service is configured; you should not make login buttons visible or active until it is true.
Ensure that your $ROOT_URL
matches the authorized domain and callback URL that you configure with the external service (for instance, if you are running Meteor behind a proxy server, $ROOT_URL
should be the externally-accessible URL, not the URL inside your proxy).
Manual service configuration
You can use Accounts.loginServiceConfiguration
to view and edit the settings collection:
import { Accounts } from "meteor/accounts-base";
Accounts.loginServiceConfiguration.find();
Popup versus redirect flow
When configuring OAuth login with a provider (such as Facebook or Google), Meteor lets you choose a popup- or redirect-based flow. In a popup-based flow, when a user logs in, they will be prompted to login at the provider in a popup window. In a redirect-based flow, the user's whole browser window will be redirected to the login provider, and the window will redirect back to your app when the login is completed.
You can also pick which type of login to do by passing an option to Meteor.loginWith<ExternalService>
Usually, the popup-based flow is preferable because the user will not have to reload your whole app at the end of the login flow. However, the popup-based flow requires browser features such as window.close
and window.opener
that are not available in all mobile environments. In particular, we recommend using Meteor.loginWith<ExternalService>({ loginStyle: 'redirect' })
in the following environments:
- Inside UIWebViews (when your app is loaded inside a mobile app)
- In Safari on iOS8 (
window.close
is not supported due to a bug)
{{ currentUser }}
Summary:
Calls Meteor.user(). Use {{#if currentUser}}
to check whether the user is logged in.
Accounts.ui.config Client only
Client only
Summary:
Configure the behavior of {{> loginButtons}}
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | Yes |
Example:
import { Accounts } from "meteor/accounts-base";
Accounts.ui.config({
requestPermissions: {
facebook: ["user_likes"],
github: ["user", "repo"],
},
requestOfflineToken: {
google: true,
},
passwordSignupFields: "USERNAME_AND_OPTIONAL_EMAIL",
});
Since Meteor 2.7 you can configure these in your Meteor settings under Meteor.settings.public.packages.accounts-ui-unstyled
.
Multi-server
The accounts-base
package exports two constructors, called AccountsClient
and AccountsServer
, which are used to create the Accounts
object that is available on the client and the server, respectively.
This predefined Accounts
object (along with similar convenience methods of Meteor
, such as Meteor.logout
) is sufficient to implement most accounts-related logic in Meteor apps. Nevertheless, these two constructors can be instantiated more than once, to create multiple independent connections between different accounts servers and their clients, in more complicated authentication situations.
AccountsCommon
Summary:
Super-constructor for AccountsClient and AccountsServer.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | an object with fields:
| Yes |
import { AccountsCommon } from "meteor/accounts-base"";
const accountsCommon = new AccountsCommon(
options
);
The AccountsClient
and AccountsServer
classes share a common superclass, AccountsCommon
. Methods defined on AccountsCommon.prototype
will be available on both the client and the server, via the predefined Accounts
object (most common) or any custom accountsClientOrServer
object created using the AccountsClient
or AccountsServer
constructors (less common).
Here are a few of those methods:
accountsCommon.userId
Summary:
Get the current user id, or null
if no user is logged in. A reactive data source.
// accountsCommon is an instance of AccountsCommon
accountsCommon.userId();
accountsCommon.user
Summary:
Get the current user record, or null
if no user is logged in. A reactive data source. In the server this fuction returns a promise.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | No |
// accountsCommon is an instance of AccountsCommon
accountsCommon.user(
options
);
accountsCommon.config
Summary:
Set global accounts options. You can also set these in Meteor.settings.packages.accounts
without the need to call this function.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | Yes |
// accountsCommon is an instance of AccountsCommon
accountsCommon.config(
options
);
From Meteor 2.5 you can set these in your Meteor settings under Meteor.settings.packages.accounts-base
. Note that due to the nature of settings file you won't be able to set parameters that require functions.
accountsCommon.onLogin
Summary:
Register a callback to be called after a login attempt succeeds.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The callback to be called when login is successful.
The callback receives a single object that
holds login details. This object contains the login
result type (password, resume, etc.) on both the
client and server. | Yes |
// accountsCommon is an instance of AccountsCommon
accountsCommon.onLogin(
() => {}
);
See description of AccountsCommon#onLoginFailure for details.
accountsCommon.onLoginFailure
Summary:
Register a callback to be called after a login attempt fails.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The callback to be called after the login has failed. | Yes |
// accountsCommon is an instance of AccountsCommon
accountsCommon.onLoginFailure(
() => {}
);
Either the onLogin
or the onLoginFailure
callbacks will be called for each login attempt. The onLogin
callbacks are called after the user has been successfully logged in. The onLoginFailure
callbacks are called after a login attempt is denied.
These functions return an object with a single method, stop
. Calling stop()
unregisters the callback.
On the server, the callbacks get a single argument, the same attempt info object as validateLoginAttempt
. On the client, the callback argument is an object containing a single error
property set to the Error
-object which was received from the failed login attempt.
accountsCommon.onLogout
Summary:
Register a callback to be called after a logout attempt succeeds.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The callback to be called when logout is successful. | Yes |
On the server, the func
callback receives a single argument with the object below. On the client, no arguments are passed.
import { AccountsCommon } from "meteor/accounts-base";
const options = {
//...
};
const accountsCommon = new AccountsCommon(options);
accountsCommon.onLogout(({ user, connection, collection }) => {
console.log(user);
// ˆˆˆˆˆˆ The Meteor user object of the user which just logged out
console.log(connection);
// ˆˆˆˆˆˆ The connection object the request came in on. See
// `Meteor.onConnection` for details.
console.log(collection);
// ˆˆˆˆˆˆ The `collection` The name of the Mongo.Collection or the
// Mongo.Collection object to hold the users.
});
AccountsClient Client only
Client only
Summary:
Constructor for the Accounts
object on the client.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | an object with fields: | Yes |
import { AccountsClient } from "meteor/accounts-base"";
const accountsClient = new AccountsClient(
options
);
At most one of options.connection
and options.ddpUrl
should be provided in any instantiation of AccountsClient
. If neither is provided, Meteor.connection
will be used as the .connection
property of the AccountsClient
instance.
Note that AccountsClient
is currently available only on the client, due to its use of browser APIs such as window.localStorage
. In principle, though, it might make sense to establish a client connection from one server to another remote accounts server. Please let us know if you find yourself needing this server-to-server functionality.
These methods are defined on AccountsClient.prototype
, and are thus available only on the client:
accountsClient.loggingIn Client only
Client only
Summary:
True if a login method (such as Meteor.loginWithPassword
, Meteor.loginWithFacebook
, or Accounts.createUser
) is currently in progress. A reactive data source.
// accountsClient is an instance of AccountsClient
accountsClient.loggingIn();
accountsClient.logout Client only
Client only
Summary:
Log the user out.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
// accountsClient is an instance of AccountsClient
accountsClient.logout(
() => {}
);
accountsClient.logoutOtherClients Client only
Client only
Summary:
Log out other clients logged in as the current user, but does not log out the client that calls this function.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
// accountsClient is an instance of AccountsClient
accountsClient.logoutOtherClients(
() => {}
);
AccountsServer Server only
Server only
Summary:
Constructor for the Accounts
namespace on the server.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
server | Object | A server object such as | Yes |
import { AccountsServer } from "meteor/accounts-base"";
const accountsServer = new AccountsServer(
server
);
These methods are defined on AccountsServer.prototype
, and are thus available only on the server:
accountsServer.validateNewUser Server only
Server only
Summary:
Set restrictions on new user creation.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Called whenever a new user is created. Takes the new user object, and returns true to allow the creation or false to abort. | Yes |
// accountsServer is an instance of AccountsServer
accountsServer.validateNewUser(
() => {}
);
This can be called multiple times. If any of the functions return false
or throw an error, the new user creation is aborted. To set a specific error message (which will be displayed by accounts-ui
), throw a new Meteor.Error
.
Example:
import { Accounts } from "meteor/accounts-base";
// Validate username, sending a specific error message on failure.
Accounts.validateNewUser((user) => {
if (user.username && user.username.length >= 3) {
return true;
} else {
throw new Meteor.Error(403, "Username must have at least 3 characters");
}
});
// Validate username, without a specific error message.
Accounts.validateNewUser((user) => {
return user.username !== "root";
});
If the user is being created as part of a login attempt from a client (eg, calling Accounts.createUser
from the client, or logging in for the first time with an external service), these callbacks are called before the Accounts.validateLoginAttempt
callbacks. If these callbacks succeed but those fail, the user will still be created but the connection will not be logged in as that user.
accountsServer.onCreateUser Server only
Server only
Summary:
Customize new user creation.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Called whenever a new user is created. Return the new user object, or throw an | Yes |
Use this when you need to do more than simply accept or reject new user creation. With this function you can programatically control the contents of new user documents.
The function you pass will be called with two arguments: options
and user
. The options
argument comes from Accounts.createUser
for password-based users or from an external service login flow. options
may come from an untrusted client so make sure to validate any values you read from it. The user
argument is created on the server and contains a proposed user object with all the automatically generated fields required for the user to log in, including the _id
.
The function should return the user document (either the one passed in or a newly-created object) with whatever modifications are desired. The returned document is inserted directly into the Meteor.users
collection.
The default create user function simply copies options.profile
into the new user document. Calling onCreateUser
overrides the default hook. This can only be called once.
Example:
import { Accounts } from "meteor/accounts-base";
// Support for playing D&D: Roll 3d6 for dexterity.
Accounts.onCreateUser((options, user) => {
const customizedUser = Object.assign(
{
dexterity: _.random(1, 6) + _.random(1, 6) + _.random(1, 6),
},
user
);
// We still want the default hook's 'profile' behavior.
if (options.profile) {
customizedUser.profile = options.profile;
}
return customizedUser;
});
accountsServer.validateLoginAttempt Server only
Server only
Summary:
Validate login attempts.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Called whenever a login is attempted (either successful or unsuccessful). A login can be aborted by returning a falsy value or throwing an exception. | Yes |
Call validateLoginAttempt
with a callback to be called on login attempts. It returns an object with a single method, stop
. Calling stop()
unregisters the callback.
When a login attempt is made, the registered validate login callbacks are called with a single argument, you can check the example:
import { AccountsServer } from "meteor/accounts-base";
const options = {
//...
};
const accountsServer = new AccountsServer(options);
accountsServer.validateLoginAttempt(
({
type, // String
allowed, // Boolean
error, // Error
user, // Object
connection, // Object
collection, // Object
methodName, // String
methodArguments, // Array<String>
}) => {
console.log(type);
// ˆˆˆˆˆˆ The service name, such as "password" or "twitter".
console.log(allowed);
// ˆˆˆˆˆˆ Whether this login is allowed and will be successful (if not aborted
// by any of the validateLoginAttempt callbacks). False if the login
// will not succeed (for example, an invalid password or the login was
// aborted by a previous validateLoginAttempt callback).
console.log(error);
// ˆˆˆˆˆˆ When `allowed` is false, the exception describing why the login
// failed. It will be a `Meteor.Error` for failures reported to the
// user (such as invalid password), and can be a another kind of
// exception for internal errors.
console.log(user);
// ˆˆˆˆˆˆ When it is known which user was attempting to login,
// the Meteor user object. This will always be present for successful logins.
console.log(connection);
// ˆˆˆˆˆˆ The `connection` object the request came in on. See
// [`Meteor.onConnection`](#meteor_onconnection) for details.
console.log(collection);
// ˆˆˆˆˆˆ The `collection` The name of the Mongo.Collection or the
// Mongo.Collection object to hold the users.
console.log(methodName);
// ˆˆˆˆˆˆ The name of the Meteor method being used to login.
// For example, "login", "loginWithPassword", or "loginWith<ExternalService>".
console.log(methodArguments);
// ˆˆˆˆˆˆ An array of the arguments passed to the login method.
// For example, `["username", "password"]`
}
);
A validate login callback must return a truthy value for the login to proceed. If the callback returns a falsy value or throws an exception, the login is aborted. Throwing a Meteor.Error
will report the error reason to the user.
All registered validate login callbacks are called, even if one of the callbacks aborts the login. The later callbacks will see the allowed
field set to false
since the login will now not be successful. This allows later callbacks to override an error from a previous callback; for example, you could override the "Incorrect password" error with a different message.
Validate login callbacks that aren't explicitly trying to override a previous error generally have no need to run if the attempt has already been determined to fail, and should start with
if (!attempt.allowed) {
return false;
}
accountsServer.beforeExternalLogin Server only
Server only
Summary:
Validate login from external service
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Called whenever login/user creation from external service is attempted. Login or user creation based on this login can be aborted by passing a falsy value or throwing an exception. | Yes |
Use this hook if you need to validate that user from an external service should be allowed to login or create account.
import { AccountsServer } from "meteor/accounts-base";
const options = {
//...
};
const accountsServer = new AccountsServer(options);
accountsServer.beforeExternalLogin(({ type, data, user }) => {
console.log(type);
// ˆˆˆˆˆˆ The service name, such as "google" or "twitter". Is a String
console.log(data);
// ˆˆˆˆˆˆ Data retrieved from the service (eg: email, name, etc)
// Is an Object.
console.log(user);
// ˆˆˆˆˆˆ If user was found in the database that matches the criteria from the service,
// their data will be provided here. Is an Object.
});
You should return a Boolean
value, true
if the login/registration should proceed or false
if it should terminate. In case of termination the login attempt will throw an error 403
, with the message: Login forbidden
.
accountsServer.setAdditionalFindUserOnExternalLogin Server only
Server only
Summary:
Customize user selection on external logins
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Called whenever a user is logged in via oauth and a user is not found with the service id. Return the user or undefined. | Yes |
When allowing your users to authenticate with an external service, the process will eventually call Accounts.updateOrCreateUserFromExternalService
. By default, this will search for a user with the service.<servicename>.id
, and if not found will create a new user. As that is not always desirable, you can use this hook as an escape hatch to look up a user with a different selector, probably by emails.address
or username
. Note the function will only be called if no user was found with the service.<servicename>.id
selector.
The function will be called with a single argument, the info object:
import { AccountsServer } from "meteor/accounts-base";
const options = {
//...
};
const accountsServer = new AccountsServer(options);
accountsServer.setAdditionalFindUserOnExternalLogin(
({ serviceName, serviceData, options }) => {
// serviceName: String
// The external service name, such as "google" or "twitter".
// serviceData: Object
// The data returned by the service oauth request.
// options: Object
// An optional arugment passed down from the oauth service that may contain
// additional user profile information. As the data in `options` comes from an
// external source, make sure you validate any values you read from it.
}
);
The function should return either a user document or undefined
. Returning a user will result in the populating the service.<servicename>
in your user document, while returning undefined
will result in a new user account being created. If you would prefer that a new account not be created, you could throw an error instead of returning.
Example:
// If a user has already been created, and used their Google email, this will
// allow them to sign in with the Meteor.loginWithGoogle method later, without
// creating a new user.
Accounts.setAdditionalFindUserOnExternalLogin(
({ serviceName, serviceData }) => {
if (serviceName === "google") {
// Note: Consider security implications. If someone other than the owner
// gains access to the account on the third-party service they could use
// the e-mail set there to access the account on your app.
// Most often this is not an issue, but as a developer you should be aware
// of how bad actors could play.
return Accounts.findUserByEmail(serviceData.email);
}
}
);
accountsServer.registerLoginHandler Server only
Server only
Summary:
Registers a new login handler.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | The type of login method like oauth, password, etc. | No |
handler | function | A function that receives an options object
(as passed as an argument to the | Yes |
// accountsServer is an instance of AccountsServer
accountsServer.registerLoginHandler(
"name", // this param is optional
() => {},
);
Use this to register your own custom authentication method. This is also used by all of the other inbuilt accounts packages to integrate with the accounts system.
There can be multiple login handlers that are registered. When a login request is made, it will go through all these handlers to find its own handler.
The registered handler callback is called with a single argument, the options
object which comes from the login method. For example, if you want to login with a plaintext password, options
could be { user: { username: <username> }, password: <password> }
,or { user: { email: <email> }, password: <password> }
.
The login handler should return undefined
if it's not going to handle the login request or else the login result object.
Rate Limiting
By default, there are rules added to the DDPRateLimiter
that rate limit logins, new user registration and password reset calls to a limit of 5 requests per 10 seconds per session. These are a basic solution to dictionary attacks where a malicious user attempts to guess the passwords of legitimate users by attempting all possible passwords.
These rate limiting rules can be removed by calling Accounts.removeDefaultRateLimit()
. Please see the DDPRateLimiter
docs for more information.
accountsServer.addDefaultRateLimit Server only
Server only
Summary:
Add a default rule of limiting logins, creating new users and password reset to 5 times every 10 seconds per connection.
// accountsServer is an instance of AccountsServer
accountsServer.addDefaultRateLimit();
accountsServer.removeDefaultRateLimit Server only
Server only
Summary:
Removes default rate limiting rule
// accountsServer is an instance of AccountsServer
accountsServer.removeDefaultRateLimit();
Passwords
The accounts-password
package contains a full system for password-based authentication. In addition to the basic username and password-based sign-in process, it also supports email-based sign-in including address verification and password recovery emails.
The Meteor server stores passwords using the bcrypt algorithm. This helps protect against embarrassing password leaks if the server's database is compromised.
To add password support to your application, run this command in your terminal:
meteor add accounts-password
In addition to configuring the
MAIL_URL
, it is critical that you set proper values (specifically thefrom
address) inAccounts.emailTemplates
to ensure proper delivery of e-mails!
You can construct your own user interface using the functions below, or use the accounts-ui
package to include a turn-key user interface for password-based sign-in.
Accounts.createUser
Summary:
Create a new user.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | Yes | |
callback | function | Client only, optional callback. Called with no arguments on success, or with a single | No |
import { Accounts } from "meteor/accounts-base";
Accounts.createUser(
options,
() => {}, // this param is optional
);
On the client, this function logs in as the newly created user on successful completion. On the server, it returns the newly created user id.
On the client, you must pass password
and at least one of username
or email
— enough information for the user to be able to log in again later. If there are existing users with a username or email only differing in case, createUser
will fail. The callback's error.reason
will be 'Username already exists.'
or 'Email already exists.'
In the latter case, the user can then either login or reset their password.
On the server, you do not need to specify password
, but the user will not be able to log in until it has a password (eg, set with Accounts.setPasswordAsync
). To create an account without a password on the server and still let the user pick their own password, call createUser
with the email
option and then call Accounts.sendEnrollmentEmail
. This will send the user an email with a link to set their initial password.
By default the profile
option is added directly to the new user document. To override this behavior, use Accounts.onCreateUser
.
This function is only used for creating users with passwords. The external service login flows do not use this function.
Instead of modifying documents in the Meteor.users
collection directly, use these convenience functions which correctly check for case insensitive duplicates before updates.
Accounts.createUserAsync
Summary:
Create a new user and returns a promise of its result.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.createUserAsync(
options
);
Accounts.createUserVerifyingEmail Server only
Server only
Summary:
Creates an user asynchronously and sends an email if options.email
is informed.
Then if the sendVerificationEmail
option from the Accounts
package is
enabled, you'll send a verification email if options.password
is informed,
otherwise you'll send an enrollment email.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | The options object to be passed down when creating the user | Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.createUserVerifyingEmail(
options
);
Accounts.setUsername Server only
Server only
Summary:
Change a user's username asynchronously. Use this instead of updating the database directly. The operation will fail if there is an existing user with a username only differing in case.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The ID of the user to update. | Yes |
newUsername | String | A new username for the user. | Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.setUsername(
"userId",
"newUsername",
);
Accounts.addEmailAsync Server only
Server only
Summary:
Asynchronously add an email address for a user. Use this instead of directly updating the database. The operation will fail if there is a different user with an email only differing in case. If the specified user has an existing email only differing in case however, we replace it.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The ID of the user to update. | Yes |
newEmail | String | A new email address for the user. | Yes |
verified | Boolean | Optional - whether the new email address should be marked as verified. Defaults to false. | No |
import { Accounts } from "meteor/accounts-base";
Accounts.addEmailAsync(
"userId",
"newEmail",
false, // this param is optional
);
By default, an email address is added with { verified: false }
. Use Accounts.sendVerificationEmail
to send an email with a link the user can use to verify their email address.
Accounts.removeEmail Server only
Server only
Summary:
Remove an email address asynchronously for a user. Use this instead of updating the database directly.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The ID of the user to update. | Yes |
String | The email address to remove. | Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.removeEmail(
"userId",
"email",
);
Accounts.verifyEmail Client only
Client only
Summary:
Marks the user's email address as verified. Logs the user in afterwards if the user doesn't have 2FA enabled.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
token | String | The token retrieved from the verification URL. | Yes |
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Accounts } from "meteor/accounts-base";
Accounts.verifyEmail(
"token",
() => {}, // this param is optional
);
If the user trying to verify the email has 2FA enabled, this error will be thrown:
- "Email verified, but user not logged in because 2FA is enabled [2fa-enabled]": No longer signing in the user automatically if the user has 2FA enabled.
This function accepts tokens passed into the callback registered with Accounts.onEmailVerificationLink
.
Accounts.findUserByUsername Server only
Server only
Summary:
Finds the user asynchronously with the specified username. First tries to match username case sensitively; if that fails, it tries case insensitively; but if more than one user matches the case insensitive search, it returns null.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
username | String | The username to look for | Yes |
options | Object | No |
import { Accounts } from "meteor/accounts-base";
/** @returns Promise<Object> */
const result = Accounts.findUserByUsername(
"username",
options, // this param is optional
);
Accounts.findUserByEmail Server only
Server only
Summary:
Finds the user asynchronously with the specified email. First tries to match email case sensitively; if that fails, it tries case insensitively; but if more than one user matches the case insensitive search, it returns null.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
String | The email address to look for | Yes | |
options | Object | No |
import { Accounts } from "meteor/accounts-base";
/** @returns Promise<Object> */
const result = Accounts.findUserByEmail(
"email",
options, // this param is optional
);
Use the below functions to initiate password changes or resets from the server or the client.
Accounts.changePassword Client only
Client only
Summary:
Change the current user's password. Must be logged in.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
oldPassword | String | The user's current password. This is not sent in plain text over the wire. | Yes |
newPassword | String | A new password for the user. This is not sent in plain text over the wire. | Yes |
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Accounts } from "meteor/accounts-base";
Accounts.changePassword(
"oldPassword",
"newPassword",
() => {}, // this param is optional
);
Accounts.forgotPassword Client only
Client only
Summary:
Request a forgot password email.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
options | Object | Yes | |
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Accounts } from "meteor/accounts-base";
Accounts.forgotPassword(
options,
() => {}, // this param is optional
);
This triggers a call to Accounts.sendResetPasswordEmail
on the server. When the user visits the link in this email, the callback registered with Accounts.onResetPasswordLink
will be called.
If you are using the accounts-ui
package, this is handled automatically. Otherwise, it is your responsibility to prompt the user for the new password and call resetPassword
.
Accounts.resetPassword Client only
Client only
Summary:
Reset the password for a user using a token received in email. Logs the user in afterwards if the user doesn't have 2FA enabled.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
token | String | The token retrieved from the reset password URL. | Yes |
newPassword | String | A new password for the user. This is not sent in plain text over the wire. | Yes |
callback | function | Optional callback. Called with no arguments on success, or with a single | No |
import { Accounts } from "meteor/accounts-base";
Accounts.resetPassword(
"token",
"newPassword",
() => {}, // this param is optional
);
This function accepts tokens passed into the callbacks registered with AccountsClient#onResetPasswordLink
and Accounts.onEnrollmentLink
.
If the user trying to reset the password has 2FA enabled, this error will be thrown:
- "Changed password, but user not logged in because 2FA is enabled [2fa-enabled]": No longer signing in the user automatically if the user has 2FA enabled.
Accounts.setPasswordAsync Server only
Server only
Summary:
Forcibly change the password for a user.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The id of the user to update. | Yes |
newPassword | String | A new password for the user. | Yes |
options | Object | No |
import { Accounts } from "meteor/accounts-base";
Accounts.setPasswordAsync(
"userId",
"newPassword",
options, // this param is optional
);
Accounts.sendResetPasswordEmail Server only
Server only
Summary:
Send an email asynchronously with a link the user can use to reset their password.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The id of the user to send email to. | Yes |
String | Optional. Which address of the user's to send the email to. This address must be in the user's | No | |
extraTokenData | Object | Optional additional data to be added into the token record. | No |
extraParams | Object | Optional additional params to be added to the reset url. | No |
import { Accounts } from "meteor/accounts-base";
/** @returns Promise<Object> */
const result = Accounts.sendResetPasswordEmail(
"userId",
"email", // this param is optional
extraTokenData, // this param is optional
extraParams, // this param is optional
);
When the user visits the link in this email, the callback registered with AccountsClient#onResetPasswordLink
will be called.
To customize the contents of the email, see Accounts.emailTemplates
.
Accounts.sendEnrollmentEmail Server only
Server only
Summary:
Send an email asynchronously with a link the user can use to set their initial password.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The id of the user to send email to. | Yes |
String | Optional. Which address of the user's to send the email to. This address must be in the user's | No | |
extraTokenData | Object | Optional additional data to be added into the token record. | No |
extraParams | Object | Optional additional params to be added to the enrollment url. | No |
import { Accounts } from "meteor/accounts-base";
/** @returns Promise<Object> */
const result = Accounts.sendEnrollmentEmail(
"userId",
"email", // this param is optional
extraTokenData, // this param is optional
extraParams, // this param is optional
);
When the user visits the link in this email, the callback registered with Accounts.onEnrollmentLink
will be called.
To customize the contents of the email, see Accounts.emailTemplates
.
Accounts.sendVerificationEmail Server only
Server only
Summary:
Send an email asynchronously with a link the user can use verify their email address.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
userId | String | The id of the user to send email to. | Yes |
String | Optional. Which address of the user's to send the email to. This address must be in the user's | No | |
extraTokenData | Object | Optional additional data to be added into the token record. | No |
extraParams | Object | Optional additional params to be added to the verification url. | No |
import { Accounts } from "meteor/accounts-base";
/** @returns Promise<Object> */
const result = Accounts.sendVerificationEmail(
"userId",
"email", // this param is optional
extraTokenData, // this param is optional
extraParams, // this param is optional
);
When the user visits the link in this email, the callback registered with Accounts.onEmailVerificationLink
will be called.
To customize the contents of the email, see Accounts.emailTemplates
.
Accounts.onResetPasswordLink Client only
Client only
Summary:
Register a function to call when a reset password link is clicked
in an email sent by
Accounts.sendResetPasswordEmail
.
This function should be called in top-level code, not inside
Meteor.startup()
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | The function to call. It is given two arguments:
| Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.onResetPasswordLink(
() => {}
);
Accounts.onEnrollmentLink Client only
Client only
Summary:
Register a function to call when an account enrollment link is
clicked in an email sent by
Accounts.sendEnrollmentEmail
.
This function should be called in top-level code, not inside
Meteor.startup()
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | The function to call. It is given two arguments:
| Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.onEnrollmentLink(
() => {}
);
Accounts.onEmailVerificationLink Client only
Client only
Summary:
Register a function to call when an email verification link is
clicked in an email sent by
Accounts.sendVerificationEmail
.
This function should be called in top-level code, not inside
Meteor.startup()
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | The function to call. It is given two arguments:
| Yes |
import { Accounts } from "meteor/accounts-base";
Accounts.onEmailVerificationLink(
() => {}
);
Accounts.emailTemplates Server only
Server only
Summary:
Options to customize emails sent from the Accounts system.
This is an Object
with several fields that are used to generate text/html for the emails sent by sendResetPasswordEmail
, sendEnrollmentEmail
, and sendVerificationEmail
.
Set the fields of the object by assigning to them:
from
: (required) AString
with an RFC5322 From address. By default, the email is sent fromno-reply@example.com
. If you want e-mails to send correctly, this should be changed to your own domain as most e-mail providers will reject mail sent fromexample.com
.siteName
: The public name of your application. Defaults to the DNS name of the application (eg:awesome.meteor.com
).headers
: AnObject
for custom email headers as described inEmail.send
.resetPassword
: AnObject
with the fields:from
: AFunction
used to override thefrom
address defined by theemailTemplates.from
field.subject
: AFunction
that takes a user object and returns aString
for the subject line of a reset password email.text
: An optionalFunction
that takes a user object and a url, and returns the body text for a reset password email.html
: An optionalFunction
that takes a user object and a url, and returns the body html for a reset password email.enrollAccount
: Same asresetPassword
, but for initial password setup for new accounts.verifyEmail
: Same asresetPassword
, but for verifying the users email address.
Example:
import { Accounts } from "meteor/accounts-base";
Accounts.emailTemplates.siteName = "AwesomeSite";
Accounts.emailTemplates.from = "AwesomeSite Admin <accounts@example.com>";
Accounts.emailTemplates.enrollAccount.subject = (user) => {
return `Welcome to Awesome Town, ${user.profile.name}`;
};
Accounts.emailTemplates.enrollAccount.text = (user, url) => {
return (
"You have been selected to participate in building a better future!" +
" To activate your account, simply click the link below:\n\n" +
url
);
};
Accounts.emailTemplates.resetPassword.from = () => {
// Overrides the value set in `Accounts.emailTemplates.from` when resetting
// passwords.
return "AwesomeSite Password Reset <no-reply@example.com>";
};
Accounts.emailTemplates.verifyEmail = {
subject() {
return "Activate your account now!";
},
text(user, url) {
return `Hey ${user}! Verify your e-mail by following this link: ${url}`;
},
};
Enable 2FA for this package
You can add 2FA to your login flow by using the package accounts-2fa. You can find an example showing how this would look like here.