Meteor logo

Skill

meteor-accounts

implement authentication in Meteor apps

Published by Meteor Updated Aug 28
Covers Auth Meteor Authentication OAuth

Description

Use when wiring up authentication in a Meteor 3 app. Triggers on accounts-password, accounts-base, OAuth (Google, Facebook, GitHub, Apple, Twitter, Meetup, Weibo), accounts-2fa, accounts-passwordless, ServiceConfiguration.configurations.upsertAsync, Accounts.createUserAsync, Accounts.setPasswordAsync, Accounts.forgotPassword, Accounts.resetPassword, Accounts.verifyEmail, useHttpOnlyCookies, clientStorage, Meteor.loginWithPasswordAnd2faCode, email verification. Use this skill when the user asks about signups, signins, or asks about token storage vs HttpOnly cookies.

SKILL.md

Meteor accounts

accounts-base plus a flavor package (accounts-password, accounts-google, etc.). Meteor stores users in Meteor.users and ships the client a resume token mapped to that document.

Decision flow

  1. Username + password? Add accounts-password.
  2. Social login? Add accounts-base plus the provider package (e.g. accounts-google) and configure the service.
  3. Magic-link? Add accounts-passwordless.
  4. 2FA? Layer accounts-2fa on top of accounts-password.
  5. Token storage on the client? Default is Web Storage. Meteor 3.3+ supports an HttpOnly cookie flow; see the section below.

Username + password

// server/accounts.js
import { Accounts } from "meteor/accounts-base";
import { Meteor } from "meteor/meteor";

Meteor.startup(() => {
  Accounts.config({
    sendVerificationEmail: true,
  });

  Accounts.emailTemplates.siteName = "My App";
  Accounts.emailTemplates.from = "no-reply@example.com";
});

The from address is required; Meteor 3.5+ logs a server warning if you omit it.

Do not set forbidClientAccountCreation: true when the client signup form calls Accounts.createUser or Accounts.createUserAsync. The server rejects that request with 403 Signups forbidden. For invite-only or administrator provisioning, set the option on both client and server, remove the public signup UI, and call Accounts.createUserAsync only from trusted server code after its own authorization check.

// client/signin.js (Meteor 3.5+)
import { Meteor } from "meteor/meteor";
import { Accounts } from "meteor/accounts-base";

async function signUp({ email, password }) {
  await Accounts.createUserAsync({ email, password });
}

async function signIn({ email, password }) {
  await Meteor.loginWithPasswordAsync(email, password);
}

Client Accounts.createUser(options, callback) also remains supported. Meteor.loginWithPasswordAsync was added in Meteor 3.5; on older 3.x use the callback form of Meteor.loginWithPassword or wrap it in a Promise.

On the server use await Accounts.createUserAsync(options) and await Accounts.setPasswordAsync(userId, newPassword).

HttpOnly cookies (Meteor 3.3+)

Default token storage is Web Storage. To move the resume token into an HttpOnly cookie and keep the client tab in-memory only:

// server
Meteor.startup(() => {
  Accounts.config({
    clientStorage: "none",
    useHttpOnlyCookies: true,
  });
});
// settings.json (public; surfaces the same flags to the client)
{
  "public": {
    "packages": {
      "accounts": {
        "clientStorage": "none",
        "useHttpOnlyCookies": true
      }
    }
  }
}

After restart and login, Meteor.loginToken* no longer appears in localStorage; the browser receives an HttpOnly meteor_login_token cookie. Each tab keeps its own in-memory credentials.

OAuth (Google example)

// server/oauth.js
import { ServiceConfiguration } from "meteor/service-configuration";

await ServiceConfiguration.configurations.upsertAsync(
  { service: "google" },
  {
    $set: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      secret: process.env.GOOGLE_CLIENT_SECRET,
      loginStyle: "popup",
    },
  },
);
// client
Meteor.loginWithGoogle(
  { requestPermissions: ["email", "profile"] },
  (err) => { if (err) console.error(err); },
);

loginStyle: "redirect" for mobile or environments without window.close / window.opener. Each provider ships its own accounts-<service> package: accounts-google, accounts-github, accounts-facebook, accounts-twitter, accounts-apple, accounts-meetup, accounts-weibo.

To encrypt OAuth secrets at rest, add oauth-encryption and pass oauthSecretKey to Accounts.config. This seals the provider application secret in ServiceConfiguration.configurations.secret and the supported provider-specific user token fields. It does not create a generic Meteor.users.services.<provider>.secret field. See meteor-security.

Email verification and reset

// client
Accounts.forgotPassword({ email }, (err) => { ... });

// reset page
Accounts.resetPassword(token, newPassword, (err) => { ... });

// verify email
Accounts.verifyEmail(token, (err) => { ... });

Customize the URL pattern that lands in the email:

Accounts.urls.resetPassword = (token) =>
  Meteor.absoluteUrl(`reset/${token}`);
Accounts.urls.verifyEmail = (token) =>
  Meteor.absoluteUrl(`verify/${token}`);

Both setters accept async functions too (Meteor 3.x).

Customize the message:

Accounts.emailTemplates.resetPassword.subject = () => "Reset your password";
Accounts.emailTemplates.resetPassword.text = (user, url) =>
  `Reset link: ${url}`;

Passwordless

Add accounts-passwordless. Request a one-time code or link, then submit the code with the same selector:

Accounts.requestLoginTokenForUser(
  {
    selector: { email },
    userData: { email },
    options: { userCreationDisabled: false },
  },
  (error) => { if (error) console.error(error); },
);

Meteor.passwordlessLoginWithToken(
  { email },
  token,
  (error) => { if (error) console.error(error); },
);

Set userCreationDisabled: true for sign-in-only flows. Configure tokenSequenceLength, loginTokenExpirationHours, and the Accounts.emailTemplates.sendLoginToken template on the server. Treat the token-request method as an abuse-sensitive endpoint and rate-limit repeated requests.

2FA

accounts-2fa adds TOTP. The login flow:

  1. Client calls Meteor.loginWithPasswordAsync(user, password) on Meteor 3.5+, or the callback form of Meteor.loginWithPassword on older 3.x.
  2. Server rejects with error.error === 'no-2fa-code'.
  3. Client prompts for a code, retries with Meteor.loginWithPasswordAnd2faCode(user, password, code, cb).

Anti-patterns

  • Store the OAuth secret in Meteor.settings.public. The client sees public. Put secrets at the top level of settings.json.
  • Build a custom password hash. accounts-password uses bcrypt; trust it.
  • Bypass forbidClientAccountCreation with a method that takes a password. Same risk.
  • Run Accounts.config({ ... }) inside a deferred path. Call it at top level or in Meteor.startup.

See also

  • references/password-flows.md
  • references/oauth-services.md
  • references/eval-cases.md
  • For OAuth-secret encryption and CSP, see the meteor-security skill.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.