Authentication
Dynamic authentication api. Extremely configurable authentication system with a default sweet spot. By itself the authentication system is agnostic to the transport used to authenticate users, you need to mount this in express routes for example, and then depending the results of the dynamics respond to your users with the adequate messages and data.
Install
npm install @universal-packages/authenticationAuthentication
The Authentication class is a descendant of DynamicApi class, it is the entry interface to load and perform all our authentication related dynamics.
import { Authentication } from '@universal-packages/authentication'
const authentication = new Authentication({ dynamicsLocation: './src', secret: 'my secret' })
await authentication.loadDynamics()
const result = await authentication.performDynamic('log-in', { credential: 'username', password: '12345678' })
console.log(result)
// > { status: 'success', authenticatable: { id: 69, username: 'username', createdAt: [Date] } }By default authentication comes packed with a whole default auth system, but we can override all or part of the system by creating non default dynamics in your dynamics location with the extension prefix auth-dynamic, ex: LogIn.auth-dynamic.js and export ad default dynamic class there. More about all the dynamics that can be override below.
Options
Authentication take options similar to DynamicApi options:
-
debugBooleanIf true the instance of this authentication dynamic api will keep track of what is being performed into a log. -
dynamicsLocationRequiredStringWhere to look up for dynamics to load withe to override default ones or new ones. -
secretRequiredStringSecret used for cryptography to generate tokens and verifying them for this authentication instance in particular. -
emailAuthenticationCredentialOptionsOptions related to email authenticationconfirmationGracePeriodStringex: 2 daysIf provided an authenticatable will need to confirm its email before this time or log in will not work until confirmed.enableConfirmationBooleanIf true all confirmation behavior will take place, like verifying grace period or if an authenticatable needs to be confirmed to continue log-in.enableCorroborationBooleanIf true before signing up the email should be corroborated.enableMultiFactorBooleanIf true, and if the authenticatable has it configured,to complete a log in with email, the authenticatable needs to verify multi-factor.enablePasswordCheckBooleandefault: trueIf true a password will be required at login if the authenticatable has it set.enableSignUPBooleandefault: trueIf true an authenticatable can sign up using tis kind of credential.enableSignUpInvitationsBooleanIf true an authenticatable can sign up using an invitation as well as sending them.enforceMultiFactorBooleanIf true, to complete a log in with email, the authenticatable always needs to verify multi-factor.enforceConfirmationBooleanIf true, an authenticatable always need to be confirmed to be able to log in.enforcePasswordCheckBooleandefault: trueIf true a password will be required at login always.enforceSignUpInvitationsBooleanIf true an authenticatable can only sign up if an invitation was issued for it.sendMultiFactorInPlaceBooleanIf true, thesend-multi-factordynamic will be performed after successfully logging in, if false, it will be need to be sent later, useful to let the user select a channel to end the multi-factor.
-
enableLockingBooleanif true, an authenticatable can be locked after several failed log in attempts. -
enableLogInCountBooleanif true, every time an authenticatable login successfully the count will be up and saved. -
maxAttemptsUntilLockNumberdefault: 5After how many failed log in attempts an authenticatable should be locked. -
multiFactorActivityLimitStringdefault: 5 minutesAfter a successful login first step, for how much time should we consider the multi factor as active?, if the time has passed the user should do the first step again. -
phoneAuthenticationCredentialOptionsOptions related to phone authenticationconfirmationGracePeriodStringex: 2 daysIf provided an authenticatable will need to confirm its phone before this time or log in will not work until confirmed (for phone usually we corroborate at sign up so this is not a dynamic commonly used).enableConfirmationBooleanIf true all confirmation behavior will take place, like verifying grace period or if an authenticatable needs to be confirmed to continue log-in.enableMultiFactorBooleandefault: trueIf true, and if the authenticatable has it configured,to complete a log in with phone, the authenticatable needs to verify multi-factor.enablePasswordCheckBooleanIf true a password will be required at login if the authenticatable has it set.enableCorroborationBooleandefault: trueIf true before signing up the phone should be corroborated.enableSignUPBooleandefault: trueIf true an authenticatable can sign up using tis kind of credential.enableSignUpInvitationsBooleanIf true an authenticatable can sign up using an invitation as well as sending them.enforceMultiFactorBooleandefault: trueIf true, to complete a log in with phone, the authenticatable always needs to verify multi-factor.enforceConfirmationBooleanIf true, an authenticatable always need to be confirmed to be able to log in.enforcePasswordCheckBooleanIf true a password will be required at login always.enforceSignUpInvitationsBooleanIf true an authenticatable can only sign up if an invitation was issued for it.sendMultiFactorInPlaceBooleanIf true, thesend-multi-factordynamic will be performed after successfully logging in, if false, it will be need to be sent later, useful to let the user select a channel to end the multi-factor.
-
providerKeys{ provider: Object }If a provider dynamic needs a set of keys here they should be placed to be read inside the dynamic. -
unlockAfterStringex: 1 hourWhen an authenticatable is locked it automatically unlocks after this time has passed. -
validationsAttributesValidationOptionsOptions related to how every assignable attribute should be validated at sign up/reset password dynamics.Defaults: - password: - size: - min: 8 - max: 256 - username: - matcher: /^[a-zA-Z.0-9_\-&]+$/i - email: - is email - uniqueness - phone: - is phone number - uniquenessemail,firstName,lastName,name,password,phone,username<attribute>ValidationOptions | falseoptionalBooleanIf true, when the value should be validated but the value is not set, the validation is not ran.matcherRegexA regex expression to validate value format.size{ min?: number; max?: number }If provided teh value length should be betweenminand/ormax.validatorRegexA validator function for a custom coded validation.
Authenticatable
Internally this auth system will handle an abstract Authenticatable class, we need to provided it in order for the whole thing to work.
import User from './User'
authentication.setAuthenticatable(User)import { Encrypt } from '@universal-packages/authentication'
export default class User {
id
profilePictureUrl
email
emailConfirmedAt
unconfirmedEmail
phone
phoneConfirmedAt
unconfirmedPhone
username
failedLogInAttempts
lockedAt
logInCount
multiFactorEnabled
multiFactorActiveAt
@Encrypt()
password
encryptedPassword
firstName
lastName
name
inviterId
createdAt
updatedAt
save() {}
static async existsWithCredential(credentialKind, credential) {}
static async existsWithUsername(username) {}
static async findById(id) {}
static async findByCredential(credential) {}
static async findByProviderId(provider, id) {}
}Decorators
Encrypt([propertyToEncrypt: string])
Use this decorator to automatically encrypt attributes in a class. For example for the password attribute, when decorated, every time is set, the encryptedPassword attribute is going to set with a hashed and salted string based on the password. It sets depending on the base attribute name encrypted<Attribute>.
import { Encrypt } from '@universal-packages/authentication'
export default class User {
@Encrypt()
secret
encryptedSecret
}
const user = new User()
user.secret = 'my password'
console.log(user.secret, user.encryptedSecret)
// > undefined C49HSl4okw8yoCKfoNRnsqD4T0T6SJZkdpTgU1o478Mk4GT995KV5HUKzvsnN1fShOo9sdDQq3Rjiz+Brj9bCIeJfWrt7tMl936wWyBARkPCdDlj9OfLNNDnhGo7dkmbU8YBfpgcmoMUmCuIftupOik+Nk/Eu83J4epW5y2w0fM=You can also specify the attribute name to store the hashed password.
import { Encrypt } from '@universal-packages/authentication'
export default class User {
@Encrypt('hashedSecret')
secret
hashedSecret
}Default main dynamics
connect-provider Async
Connects an authenticatable with provider (sets and identifier so we know they are connected).
const result = authentication.perform('connect-provider', { authenticatable, provider: 'github', token: 'token' })PAYLOADObjectauthenticatableAuthenticatableproviderStringtokenString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?already-connectedprovider-error
continue-with-provider Async
It validates the provider and gets the user data and either, gets the user already connected and returns it or create a new one with provider user data.
const result = authentication.perform('continue-with-provider', { provider: 'github', token: 'token' })PAYLOADObjectproviderStringtokenString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?already-connectedwarningprovider-errorfailure
invite-authenticatable Async
Creates an invitation and performs the send-invitation dynamic passing the invitation.
const result = authentication.perform('invite-authenticatable', { provider: 'github', token: 'token' })PAYLOADObjectcredentialStringcredentialKindemail | phoneinviterIdString | Number | BigInt
RESULTAuthenticationResultmessage?invitations-disabledfailure
log-in Async
Verifies credentials and if all configured behavior is positive it returns the authenticatable for which the credentials matched.
const result = authentication.perform('log-in', { credential: 'username | email | phone', password: 'password' })PAYLOADObjectcredentialStringpasswordString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?confirmation-requiredwarningmulti-factor-inboundwarningmulti-factor-waitingwarninginvalid-credentialsfailurelockedfailure
request-confirmation Async
Generates a confirmation and performs the send-confirmation dynamic passing the one time password.
This happens when signing up and the confirmation is pending, or when time has passed and a user request it manually.
const result = authentication.perform('request-confirmation', { credential: 'email', credentialKind: 'email' })PAYLOADObjectcredentialStringcredentialKindemail | phone
RESULTAuthenticationResultmessage?confirmation-disabledfailure
request-corroboration Async
Generates a corroboration and performs the send-corroboration dynamic passing the one time password..
This happens when signing up requires pre confirmation of credential, the user first request a confirmation.
const result = authentication.perform('request-confirmation', { credential: 'phone', credentialKind: 'phone' })PAYLOADObjectcredentialStringcredentialKindemail | phone
RESULTAuthenticationResultmessage?corroboration-disabledfailure
request-multi-factor Async
Generates a multi factor and performs the send-multi-factor dynamic passing the one time password.
This happens when logging in and when the user request another one time password to continue logging in.
const result = authentication.perform('request-multi-factor', { credential: 'email' })PAYLOADObjectcredentialString
RESULTAuthenticationResultmessage?nothing-to-dowarning
request-password-reset Async
Generates a password reset and performs the send-password-reset dynamic passing the one time password.
const result = authentication.perform('request-password-reset', { credential: 'email' })PAYLOADObjectcredentialString
RESULTAuthenticationResultmessage?nothing-to-dowarning
request-unlock Async
Generates an unlock and performs the send-multi-factor dynamic passing the one time password.
const result = authentication.perform('request-unlock', { authenticatable, credentialKind: 'email' })PAYLOADObjectauthenticatableAuthenticatable
RESULTAuthenticationResultmessage?nothing-to-dowarning
sign-up Async
Validates sign up attributes, invitation or corroboration and if all configured behavior is valid creates the new authenticatable.
const result = authentication.perform('sign-up', { attributes: { email: 'some email', password: 'some password' }, credentialKind: 'email', corroborationToken: 'token' })PAYLOADObjectattributesAssignableAttributesattributesAssignableAttributesemailStringif credentialKind is emailusernameStringphoneStringif credentialKind is phonepasswordStringpresence depend on validationfirstNameStringpresence depend on validationlastNameStringpresence depend on validationnameString
credentialKindemail | phonecorroborationTokenStringoptionalinvitationTokenStringoptional
RESULTAuthenticationResultauthenticatableAuthenticatablemetadataObjectcredentialStringcredentialKindemail | phone
validationValidationResultfailurevalidBooleanerrorsObject<attribute>String[]
message?invalid-invitationfailureinvitation-requiredfailureinvalid-corroborationfailurecorroboration-requiredfailureconfirmation-inboundwarningmetadata
update-authenticatable Async
Validates and updates an authenticatable with new attributes.
const result = authentication.perform('update-authenticatable', { attributes: { firstName: 'Pepé' }, authenticatable })PAYLOADObjectattributesAssignableAttributesattributesAssignableAttributesusernameStringpasswordStringfirstNameStringlastNameStringnameStringprofilePictureUrlStringmultiFactorEnabledBoolean
authenticatableAuthenticatable
RESULTAuthenticationResultauthenticatableAuthenticatablevalidationValidationResultfailurevalidBooleanerrorsObject<attribute>String[]
update-credential Async
Validates and updates an authenticatable credential, taking corroboration and confirmation into account.
const result = authentication.perform('update-credential', { credential: 'phone-like', credentialKind: 'phone' })PAYLOADObjectauthenticatableAuthenticatablecorroborationTokenStringoptionalcredentialStringcredentialKindemail | phone
RESULTAuthenticationResultauthenticatableAuthenticatablevalidationValidationResultfailurevalidBooleanerrorsObject<attribute>String[]
update-credential Async
Validates and updates an authenticatable credential
const result = authentication.perform('update-credential', { credential: 'phone-like', credentialKind: 'phone' })PAYLOADObjectcredentialStringcredentialKindemail | phone
RESULTAuthenticationResultauthenticatableAuthenticatablevalidationValidationResultfailurevalidBooleanerrorsObject<attribute>String[]
verify-confirmation Async
Confirms an authenticatable if the one time password id valid.
const result = authentication.perform('verify-confirmation, { credential: 'email', credentialKind: 'email', oneTimePassword: '123456' })PAYLOADObjectcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?invalid-one-time-passwordfailure
verify-corroboration Async
Corroborates a credential if the one time password id valid, credential must be the authenticatable credential not the unconfirmed one even if the the one meant to confirm is that one, it is going to be taken from the authenticatable itself.
const result = authentication.perform('verify-corroboration', { credential: 'email', credentialKind: 'email', oneTimePassword: '123456' })PAYLOADObjectcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTAuthenticationResultmetadataObjectcorroborationTokenString
message?invalid-one-time-passwordfailure
verify-multi-factor Async
Verifies a multi-factor and let the logging in continue if all configured behavior is valid.
const result = authentication.perform('verify-multi-factor', { credential: 'email', credentialKind: 'email', oneTimePassword: '123456' })PAYLOADObjectidentifierStringoneTimePasswordString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?invalid-one-time-passwordfailureconfirmation-requiredwarning
verify-password-reset Async
Verifies a password reset and sets a new password
const result = authentication.perform('verify-password-reset', { credential: 'email', credentialKind: 'email', oneTimePassword: '123456', password: 'new password' })PAYLOADObjectidentifierStringoneTimePasswordStringpasswordString
RESULTAuthenticationResultvalidationValidationResultfailurevalidBooleanerrorsObject<attribute>String[]
message?invalid-one-time-passwordfailure
verify-unlock Async
Verifies an unlock and unlocks the authenticatable.
const result = authentication.perform('verify-unlock', { credential: 'email', credentialKind: 'email', oneTimePassword: '123456' })PAYLOADObjectidentifierStringoneTimePasswordString
RESULTAuthenticationResultauthenticatableAuthenticatablemessage?invalid-one-time-passwordfailure
Default extended dynamics
The extended dynamics are meant to be override in case your Authenticatable behaves differently of what this authentication defaults expect, for example if we set the password of an authenticatable in a custom manner of if we save it differently than expected.
authenticatable-from-credential
PAYLOADObjectcredentialString
RESULTAuthenticatable
authenticatable-from-id
PAYLOADObjectidString | Number | BigInt
RESULTAuthenticatable
authenticatable-from-provider-id
PAYLOADObjectproviderStringidString | Number | BigInt
RESULTAuthenticatable
authenticatable-from-provider-user-data
PAYLOADObjectproviderStringattributesProviderDataAttributesidString | Number | BigIntemailStringfirstNameStringlastNameStringnameStringprofilePictureUrlStringusernameString
RESULTAuthenticatable
authenticatable-from-sign-up
PAYLOADObjectattributesAssignableAttributesemailStringfirstNameStringlastNameStringnameStringpasswordStringphoneStringusernameString
credentialKindemail | phonecorroborationCorroborationcredentialStringcredentialKindemail | phone
invitationInvitationcredentialStringcredentialKindemail | phoneinviterIdString | Number | BigIntmetadataObject
RESULTAuthenticatable
consume-invitation
PAYLOADObjectauthenticatableAuthenticatableinvitationInvitationcredentialStringcredentialKindemail | phoneinviterIdString | Number | BigIntmetadataObject
RESULTvoid
credential-kind-from-credential-authenticatable
PAYLOADObjectauthenticatableAuthenticatablecredentialString
RESULTemail | phone
decrypt-corroboration-token
PAYLOADObjecttokenString
RESULTCorroborationcredentialStringcredentialKindemail | phone
decrypt-invitation-token
PAYLOADObjecttokenString
RESULTInvitationcredentialStringcredentialKindemail | phoneinviterIdString | Number | BigIntmetadataObject
does-authenticatable-have-password?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
does-authenticatable-requires-multi-factor?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
encrypt-corroboration
PAYLOADObjectcorroborationCorroborationcredentialStringcredentialKindemail | phone
RESULTString
encrypt-invitation
PAYLOADObjectinvitationInvitationcredentialStringcredentialKindemail | phoneinviterIdString | Number | BigIntmetadataObject
RESULTString
generate-concern-secret
PAYLOADObjectconcernconfirmation | corroboration | invitation | log-in | multi-factor | password-reset | sign-up | unlockidentifierString
RESULTString
generate-multi-factor-metadata
PAYLOADObjectauthenticatableAuthenticatable
RESULTMultiFactorMetadataidentifierStringemailStringphoneString
generate-one-time-password
PAYLOADObjectconcernconfirmation | corroboration | invitation | log-in | multi-factor | password-reset | sign-up | unlockidentifierString
RESULTString
has-authenticatable-confirmation-passed-grace-period?
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTBoolean
is-authenticatable-confirmed?
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTBoolean
is-authenticatable-connected?
PAYLOADObjectauthenticatableAuthenticatableproviderString
RESULTBoolean
is-authenticatable-lockable?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
is-authenticatable-locked?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
is-authenticatable-multi-factor-active?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
is-authenticatable-password?
PAYLOADObjectauthenticatableAuthenticatablepasswordString
RESULTBoolean
is-authenticatable-ready-to-unlock?
PAYLOADObjectauthenticatableAuthenticatable
RESULTBoolean
save-authenticatable
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
send-confirmation
PAYLOADObjectcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTvoid
send-confirmation-thanks
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTvoid
send-corroboration
PAYLOADObjectcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTvoid
send-invitation
PAYLOADObjectcredentialStringcredentialKindemail | phoneinvitationTokenString
RESULTvoid
send-multi-factor
PAYLOADObjectidentifierStringcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTvoid
send-password-reset
PAYLOADObjectidentifierStringcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTvoid
send-unlock
PAYLOADObjectcredentialStringcredentialKindemail | phoneoneTimePasswordString
RESULTvoid
send-welcome
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTvoid
set-authenticatable-attributes
PAYLOADObjectauthenticatableAuthenticatableattributesAssignableAttributesfirstNameStringlastNameStringmultiFactorEnabledStringnameStringpasswordStringprofilePictureUrlStringusernameString
includeAttributeName[]excludeAttributeName[]
RESULTvoid
set-authenticatable-confirmed
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTvoid
set-authenticatable-fail-attempt
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
set-authenticatable-locked
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
set-authenticatable-log-in-count
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
set-authenticatable-multi-factor-active
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
set-authenticatable-multi-factor-inactive
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
set-authenticatable-password
PAYLOADObjectauthenticatableAuthenticatablepasswordString
RESULTvoid
set-authenticatable-profile-picture
PAYLOADObjectauthenticatableAuthenticatablepictureUrlString
RESULTvoid
set-authenticatable-provider-id
PAYLOADObjectauthenticatableAuthenticatableproviderStringidString | Number | BigInt
RESULTvoid
set-authenticatable-unconfirmed-credential
PAYLOADObjectauthenticatableAuthenticatablecredentialStringcredentialKindemail | phone
RESULTvoid
set-authenticatable-unlocked
PAYLOADObjectauthenticatableAuthenticatable
RESULTvoid
stablish-authenticatable-unconfirmed-credential
PAYLOADObjectauthenticatableAuthenticatablecredentialKindemail | phone
RESULTvoid
validate-attributes
PAYLOADObjectattributesAssignableAttributesemailStringfirstNameStringlastNameStringnameStringpasswordStringphoneStringusernameString
includeAttributeName[]excludeAttributeName[]allOptionalBoolean
RESULTValidationResultvalidBooleanerrorsObject<attribute>String[]
verify-one-time-password
PAYLOADObjectconcernconfirmation | corroboration | invitation | log-in | multi-factor | password-reset | sign-up | unlockcredentialStringcredentialKindemail | phoneoneTimePasswordemail | phone
RESULTBoolean
Typescript
This library is developed in TypeScript and shipped fully typed.
Contributing
The development of this library happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving this library.