Accounts

Adds custom account registration, authentication, and verification.

const Accounts = org.objects.accounts;
// or import Accounts from 'accounts'; 

// find first readable account.
Accounts.find().paths('email').next().email; 

// script principal is an Account instance.
script.principal.update('name.first', 'Myself');

Methods

failAuth()

Record an audit record failed authentication attempt in the logs. Developers should call this after a custom authentication failure. This will increment the auth attempts counter and lock the account if required. Always throws either kInvalidCredentials or kAccountLocked.

Additionally, an account locked notification is sent to the account holder if the account is locked.

Arguments

  • email (String) The account login email address.

login(payload, options)

Enables account login through a script. Use in conjunction with preAuth and failAuth to use the built-in authentication failure lock-out mechanism.

Arguments

  • payload (Object) Uses the same options as the Login endpoint. Though password may be omitted if the passwordLess options is set.

  • options (Object)

    • passwordLess (Bool) If true, skips password check.

    • verifyLocation (Bool) Defaults to true. When false, 2fa based on location md.fingerprint is completely ignored. Useful for SSO scenarios where 2fa would presumably be handled by the identify provider.

Returns

principal (Object)

  • _id (ObjectId) The identifier of the principal who called the script

  • email (String) The principal's email address

  • name (Object)

    • first (String) The principal's first name

    • last (String) The principal's last name

  • roles (ObjectId[]) A list of the principal's assigned org roles

accounts.login() is only available in Route scripts

preAuth(email)

Checks to ensure the account exists and is not locked. throws kInvalidCredentials or kAccountLocked.

Arguments

  • email (String) The account login email address.

Returns

  • account (Account) The Account object as read by the account itself.

register(payload, options)

Enables account provisioning through a script, bypassing the org's self-registration setting.

This version requires that a request be present and must be called from a route.

Arguments

  • payload (Object) Uses the same options as the Registration endpoint.

  • options (Object)

    • skipVerification (Bool) Set new account state to 'verified'. Normally, initial account state is 'unverified' and an account is verified through an email link that includes a verification token. Unverified accounts cannot create connections or be connection targets.

    • skipActivation (Bool) Skip activation when an org is configured to require activation prior to login.

    • skipNotification (Bool) Suppress provisioned account password reset welcome email for newly provisioned accounts.

    • requireMobile (Bool) Defaults to true. If false, an account can be created without a mobile number.

    • requireMobile (Bool) Defaults to true. If false, an account can be created without a mobile number.

    • verifyLocation (Bool) When provisioning an account whose caller is the target of the account creation, the md.fingerprint cookie will be created and the current location verified automatically.

Returns

  • account (Account) The account object as read by the newly registered account holder.

provision(payload, options)

Offline account provisioning.

Arguments

  • payload (Object) Uses the same options as the Registration endpoint.

  • options (Object)

    • skipActivation (Bool) Skip activation when an org is configured to require activation prior to login.

    • sendWelcomeEmail (Bool) Set to false to suppress provisioned account password reset welcome email.

Returns

  • account (Account) The account object as read by the newly registered account holder.

createAuthToken(apiKey, subject, options)

See Token Authentication and Scoping for more information about scopes and jwt claims.

Creates a JWT access token used for scoped access the api.

Arguments

  • apiKey (String) The api key of the issuing application

  • subject (String|ObjectID) The account identifier or email address for which the token is issued. Using the token will authenticate the caller as the subject.

  • options (Object)

    • activatesIn (Number) Optional number of seconds until the token activates. Incompatible with validAt, and expiresIn must exist to use this option.

    • validAt (Date) The date when the token activates. Incompatible with activatesIn, and expiresIn must exist to use this option.

    • expiresIn (Number) Optional number of seconds the token will be active, between 1 and the app's authDuration setting (typically 900). Incompatible with permanent, and defaults to authDuration.

    • grant (Number) Increases the grant level for all operations. Use with extreme care.

    • maxUses (Number) Limits the number of times the token can be authorized. Sets the 'jti' claim, so limited-use tokens can be revoked.

    • permanent (Bool) If true, creates an auth token that can be used forever and can be revoked by token id or by regenerating the app's RSA key pair. Incompatible with expiresIn.

    • roles (ObjectID[]) Additional roles granted to the token subject at runtime.

    • scope (String[]) Scopes to which the token is limited. If no scopes are passed, [] is assumed, which renders the token next to useless unless there are scoped roles.

    • skipAcl (Bool) Set to true to bypass Object defaultAcl for matching objects. A grant is still required to allow property access. Use with extreme care.

    • bypassCreateAcl (Bool) Set to true to bypass an Object createAcl. Use with extreme care.

  • includeEmail (Bool) Sets the "cortex/eml" claim, allowing username lookup.

decodeAuthToken(token)

Decodes an auth token into a human-readable JSON document.

Arguments

  • token (String) The JWT access token.

Returns token (Object) The decoded JWT access tokenJSON

{
  "aud": "https://api.dev.medable.com/example/v2",
  "cortex/gnt": 4,
  "cortex/scp": [
    "object.read.account.58ffcf06f0d11f3788826fcf.name",
    "object.read.c_messages.*.c_subject"
  ],
  "cortex/skp": true,
  "exp": 1498674945,
  "iat": 1498674045,
  "iss": "H2gFRtKGyLKvSEdOf5aYpf",
  "sub": "58ffcf06f0d11f3788826fcf"
}

authorizeToken(token)

Authorizes an access token and returns the resulting account principal. Typically, calls into the api are already authenticated (using the Authorization request header). This method exists mainly for developer use in debugging token authentication and scoping.

Arguments

  • token (String) The JWT access token.

Returns principal (Object)

revokeAuthToken(tokenOrId)

Revoke a permanent or limited-use auth token by token or jti. Only tokens creates using the permanent or maxUses options can be revoked.

Arguments

  • tokenOrId (String|ObjectID) The JWT access token or jti claim value.

Returns revoked (Bool) True is revoked, false if the token does not exist.

getSubjectTokens(apiKey, subject)

Retrieves details of active permanent and limited-use auth tokens for a subject.

Arguments

  • apiKey (String) The api key of the issuing application.

  • subject (String|ObjectID) The account identifier or email address for which the token was issued.

Returns details[] (Object[])

  • jti (String) The unique token identifier

  • last_accessed (Date) The date the token was last authorized (does not exist until the first access)

  • times_accessed (Number) The number of times the token was authorized (does not exist for limited-use tokens)

  • uses_remaining (Number) The remaining number of times the token can be authorized

[
  {
    "_id": "59486e7f53c603e8688cb5f7",
    "last_authorized": "2017-06-28T17:10:26.249Z",
    "times_authorized": 304
  },
  {
    "_id": "5953ebc9749219f1a2eedc57",
    "times_authorized": 0
  },
  {
    "_id": "595415684cffa322569c4820",
    "expires_at": "2017-06-28T21:00:28.000Z",
    "uses_remaining": 3
  }
]

revokeSubjectTokens(apiKey, subject)

Revokes all permanent or limited-use tokens for a subject.

Arguments

  • apiKey (String) The api key of the issuing application.

  • subject (String|ObjectID) The account identifier or email address for which the token was issued.

Returns revoked (Number) The count of revoked tokens.

inAuthScope(compiledScope, scopeString, matchPrefix)

Checks if a scope string is within the purview of a compiled scope.

Arguments

  • compiledScope (Object[]) The compiled principal scope. Can be retrieved through script.principal.scope or org.objects.accounts.authorizeToken(token).scope.

  • scopeString (String) The scope string to check (eg. object.read.c_messages).

  • matchPrefix (String) Defaults to true. If false, requires an exact match all the way down the chain. For example, object.read.c_messages will not match a compiled scope with object.read.c_messages.*.c_subject when false.

Returns in_scope (Boolean) True if the scopeString is within the compiled scope.

Examples

Creating and testing auth scope.JavaScript

require('should');

const token =  org.objects.account.createAuthToken(
  'H2gFRtKGyLKvSEdOf5aYpf',
  'james@medable.com',
  {
    scope: [      
      "object.read.c_messages.*.c_subject"
    ]    
  }
)

const principal = org.objects.account.authorizeToken(token);

org.objects.account.inAuthScope(principal.scope, 'object.read.c_messages', true).should.equal(true);

org.objects.account.inAuthScope(principal.scope, 'object.read.c_messages', false).should.equal(false);

Custom registration: Here we have an example custom registration script. It takes a request body that contains the necessary properties to register an account, registers that account, logs that user in, and returns the account object.Custom Registration

import accounts from 'accounts';
import request from 'request';

/* example request body
{
  email: 'GordonDownie@TheTragicallyHip.com',
  name: {
      first: 'Gordon',
      last: 'Downie'
  },
  mobile: '+15555555555',
  password: 'new orleans is sinking, man, and i don\'t wanna swim',
  roles:[customRoleId]
}
*/

const options = {
    skipVerification: true,
    skipActivation: true,
    skipNotification: true,
    verifyLocation: true
};

let account = accounts.register(request.body, options);

// verifyLocation ensures the caller is logged in without a kNewLocation fault.
let principal = accounts.login({
    email: account.email
}, {
    passwordLess: true
});

return account;

Custom authentication: Here we have a custom authentication script that checks with a third-party authentication system, and if successful authenticates the user. This type of custom authentication can be useful for single sign-on use cases or where user identity is managed via an external provider.

Custom Authentication

import req from 'request';
import accounts from 'accounts';
import http from 'http';

const payload = {
    email: req.body.email
};

// this checks for account existence and lock. should be called prior to custom authentication.
let account = accounts.preAuth(req.body.email);

// custom authentication here (token is some sort of 3rd party auth token).
let response = http.post('https://my.login.com/auth_me', {token: req.body.token});

// if authentication fails, increment attempts, fail and throw.
if (response.body.err) {
    accounts.failAuth(req.body.email, response.body.err);
}

// was there a 2fa location verification code attached?
if (req.body.code) {
    payload.location = {
        verificationToken: req.body.code
    };
}

// login without a password. note that the account 'clientKey' cannot be attached when no password is used.
return accounts.login(payload, {
    passwordLess: true
});

Last updated