mcpField
M
meteor-accounts

meteor-accounts

github.com/meteorDevelopment10292 installsUpdated 5d ago
Repository

About meteor-accounts

A skill for configuring Meteor accounts, covering password, OAuth, passwordless, two-factor authentication, token storage, and email flows. It guides Meteor developers through choosing account packages and handling configuration and security considerations.

Key features

  1. 01Password and account creation flows
  2. 02OAuth provider configuration
  3. 03Passwordless login tokens
  4. 04TOTP two-factor login
  5. 05HttpOnly cookie token storage
  6. 06Email verification and reset

Use cases

  1. 01Choosing an authentication package for a Meteor app
  2. 02Adding Google or other provider sign-in
  3. 03Moving resume tokens to HttpOnly cookies
  4. 04Implementing passwordless or TOTP sign-in

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/meteor/agent-skills --skill meteor-accounts

After installing, type/meteor-accountsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
eval-cases.md
http-only-cookies.md
oauth-services.md
password-flows.md
passwordless-requests.md
users-collection.md

Details

From the project README

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.

For a custom users collection, configure both runtimes before app reads or validators. The 3.6 RC fixes collection setup and publication lookup; review collection identity and client-write policy before changing profile rules.

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 = "[email protected]";
});

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. DDP authentication still reads the resume token into memory; this does not protect it from a malicious script already executing in the application origin.

With [email protected] (Meteor 3.5.2), the server handles cookie endpoints only when it is opted in too. A client-only setting can therefore produce an HTML response or 404 from later handlers. The /set body limit is 4096 bytes; larger requests return HTTP 413. See cookie endpoint troubleshooting for the routes, version boundary, and diagnostic checks. Meteor 3.6-beta.1's [email protected] also requires trusted origins and valid tokens, uses SameSite=Strict, and adds a separate per-address endpoint rate limit. Review custom callers and cross-site entry flows before upgrading. The RC uses [email protected]; distinguish invalid sessions from transient or rate-limit responses before retrying or discarding 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. With Meteor 3.6-beta.1's [email protected] and [email protected], the complete request is validated before lookup/creation and joins the default Accounts DDP rate rule. See passwordless request boundaries for custom callers and earlier packages. The RC pairs [email protected] with [email protected]; retain the default limiter and handle callback errors without an immediate retry loop.

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.

Comments

Markdown supported