Account client API for the browser
hoodie-account-client
is a JavaScript client for the Account JSON API.
It persists session information in localStorage (or your own store API) and
provides front-end friendly APIs for things like creating a user account,
confirming, resetting a password, changing profile information, or closing the account.
// Account loaded via <script> or require('@hoodie/account-client')
var account = new Account('https://example.com/account/api')
// check if user is signed in
account.get('session').then(function (session) {
if (session) {
renderDashboard()
} else {
renderWelcome()
}
})
account.on('signout', redirectToHome)
new Account(options)
Argument | Type | Description | Required |
---|---|---|---|
options.url |
String | Path or full URL to root location of the account JSON API | Yes |
options.id |
String | The initial account id can be passed. Useful for apps that can be used locally without an account. | Defaults to random id |
options.cacheKey |
String |
Name of localStorage key where to persist the session cache. Not used
if options.cache is passed.
|
Defaults to account |
options.cache |
Object |
Object with .get() , .set(properties) and
.unset() methods to persist the account status. Each method
must return a promise, .get() resolves with the account’s
properties or an empty object.
|
Defaults to a localStorage-based API, see also options.cacheKey |
options.validate |
Function | Optional function to validate account before sending sign up / sign in / update requests | No |
Returns account
API.
Example
new Account({
url: '/api',
id: 'user123',
cacheKey: 'myapp.session',
validate: function (options) {
if (options.username.length < 3) {
throw new Error('Username must have at least 3 characters')
}
}
})
Calls the function passed into the Constructor.
Returns a Promise that resolves to true
by default
account.validate(options)
Argument | Type | Required |
---|---|---|
options.username |
String | No |
options.password |
String | No |
options.profile |
Object | No |
Resolves with an argument.
Rejects with any errors thrown by the function originally passed into the Constructor.
Example
var account = new Account({
url: '/api',
cacheKey: 'app.session',
validate: function (options) {
if (options.password.length < 8) {
throw new Error('password should contain at least 8 characters')
}
}
})
account.validate({
username: 'DocsChicken',
password: 'secret'
})
.then(function () {
console.log('Successfully validated!')
})
.catch(function (error) {
console.log(error) // should be an error about the password being too short
})
Creates a new user account on the Hoodie server. Does not sign in the user automatically, account.signIn must be called separately.
account.signUp(accountProperties)
Argument | Type | Required |
---|---|---|
accountProperties.username |
String | Yes |
accountProperties.password |
String | Yes |
Resolves with accountProperties
:
{
"id": "account123",
"username": "pat",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-01T00:00.000Z"
}
Rejects with:
InvalidError |
Username must be set |
---|---|
SessionError |
Must sign out first |
ConflictError |
Username <username> already exists |
ConnectionError |
Could not connect to server |
Example
account.signUp({
username: 'pat',
password: 'secret'
}).then(function (accountProperties) {
alert('Account created for ' + accountProperties.username)
}).catch(function (error) {
alert(error)
})
🐕 Implement account.signUp with profile: {…} option: #11
Creates a user session
account.signIn(options)
Argument | Type | Description | Required |
---|---|---|---|
options.username |
String | - | Yes |
options.password |
String | - | Yes |
Resolves with accountProperties
:
{
"id": "account123",
"username": "pat",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-02T00:00.000Z",
"profile": {
"fullname": "Dr. Pat Hook"
}
}
Rejects with:
UnconfirmedError |
Account has not been confirmed yet |
---|---|
UnauthorizedError |
Invalid Credentials |
Error |
A custom error set on the account object, e.g. the account could be blocked due to missing payments |
ConnectionError |
Could not connect to server |
Example
account.signIn({
username: 'pat',
password: 'secret'
}).then(function (sessionProperties) {
alert('Ohaj, ' + sessionProperties.account.username)
}).catch(function (error) {
alert(error)
})
Deletes the user’s session
account.signOut()
Resolves with sessionProperties
like account.signin,
but without the session id:
{
"account": {
"id": "account123",
"username": "pat",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-02T00:00.000Z",
"profile": {
"fullname": "Dr. Pat Hook"
}
}
}
Rejects with:
Error |
A custom error thrown in a before:signout hook |
---|
Example
account.signOut().then(function (sessionProperties) {
alert('Bye, ' + sessionProperties.account.username)
}).catch(function (error) {
alert(error)
})
Destroys the account of the currently signed in user.
account.destroy()
Resolves with sessionProperties
like account.signin,
but without the session id:
{
"account": {
"id": "account123",
"username": "pat",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-02T00:00.000Z",
"profile": {
"fullname": "Dr. Pat Hook"
}
}
}
Rejects with:
Error |
A custom error thrown in a before:destroy hook |
---|---|
ConnectionError |
Could not connect to server |
Example
account.destroy().then(function (sessionProperties) {
alert('Bye, ' + sessionProperties.account.username)
}).catch(function (error) {
alert(error)
})
Returns account properties from local cache or fetches them from remote. Fetches properties from remote unless
id
and or session
properties are requestedoptions.local
is set to trueaccount.get(properties, options)
Argument | Type | Description | Required |
---|---|---|---|
properties |
String or Array of strings | When String, only this property gets returned. If array of strings, only passed properties get returned | No |
options.local |
Boolean | When set to true then only the properties from local cache are returned. | No |
Resolves with object with account properties or value of passed path, depending
on the properties
argument passed
Examples
account.get().then(function (properties) {
alert('You signed up at ' + properties.createdAt)
})
account.get('createdAt').then(function (createdAt) {
alert('You signed up at ' + createdAt)
})
account.get(['username', 'createdAt']).then(function (properties) {
alert('Hello ' + properties.username + '! You signed up at ' + properties.createdAt)
})
account.get({local: true}).then(function (cachedProperties) {
// ...
})
account.get('session').then(function (session) {
if (session) {
// user is signed in
} else {
// user is signed out
}
})
account.get('session.invalid').then(function (hasInvalidSession) {
if (hasInvalidSession) {
// user is signed in but has an expired or otherwise invalidated session
}
})
Update account properties on server and local cache
account.update(changedProperties)
Argument | Type | Description | Required |
---|---|---|---|
changedProperties |
Object | Object of properties & values that changed. Other properties remain unchanged. | No |
Resolves with accountProperties
:
{
"id": "account123",
"username": "pat",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-01T00:00.000Z"
}
Rejects with:
UnauthenticatedError |
Session is invalid |
---|---|
InvalidError |
Custom validation error |
ConflictError |
Username <username> already exists |
ConnectionError |
Could not connect to server |
Example
account.update({username: 'treetrunks'}).then(function (properties) {
alert('You are now known as ' + properties.username)
})
Returns account properties from local cache or fetches them from remote.
account.profile.get(properties)
Argument | Type | Description | Required |
---|---|---|---|
properties |
String or Array of strings | When String, only this property gets returned. If array of strings, only passed properties get returned. Property names can have `.` separators to return nested properties. | No |
options.local |
Boolean | When set to true then only the properties from local cache are returned. | No |
Resolves with profile properties, falls back to empty object {}
. If a single
string is passed as properties
then resolves with value for that property.
Examples
account.profile.get().then(function (properties) {
alert('Hey there ' + properties.fullname)
})
account.profile.get('fullname').then(function (fullname) {
alert('Hey there ' + fullname)
})
account.profile.get(['fullname', 'address.city'], {local: true}).then(function (properties) {
alert('Hey there ' + properties.fullname + '. How is ' + properties.address.city + '?')
})
Update profile properties on server and local cache
account.profile.update(changedProperties)
Argument | Type | Description | Required |
---|---|---|---|
changedProperties |
Object | Object of properties & values that changed. Other properties remain unchanged. | No |
Resolves with profileProperties
:
{
"id": "account123-profile",
"fullname": "Dr Pat Hook",
"address": {
"city": "Berlin",
"street": "Adalberststraße 4a"
}
}
Rejects with:
UnauthenticatedError |
Session is invalid |
---|---|
InvalidError |
Custom validation error |
ConnectionError |
Could not connect to server |
Example
account.profile.update({fullname: 'Prof Pat Hook'}).then(function (properties) {
alert('Congratulations, ' + properties.fullname)
})
Sends a custom request to the server, for things like password resets, account upgrades, etc.
account.request(properties)
Argument | Type | Description | Required |
---|---|---|---|
properties.type |
String | Name of the request type, e.g. "passwordreset" | Yes |
properties |
Object | Additional properties for the request | No |
Resolves with requestProperties
:
{
"id": "request123",
"type": "passwordreset",
"contact": "pat@example.com",
"createdAt": "2016-01-01T00:00.000Z",
"updatedAt": "2016-01-01T00:00.000Z"
}
Rejects with:
ConnectionError |
Could not connect to server |
---|---|
NotFoundError |
Handler missing for "passwordreset" |
InvalidError |
Custom validation error |
Example
account.request({type: 'passwordreset', contact: 'pat@example.com'}).then(function (properties) {
alert('A password reset link was sent to ' + properties.contact)
})
account.on(event, handler)
Example
account.on('signin', function (accountProperties) {
alert('Hello there, ' + accountProperties.username)
})
Call function once at given account event.
account.one(event, handler)
Example
account.one('signin', function (accountProperties) {
alert('Hello there, ' + accountProperties.username)
})
Removes event handler that has been added before
account.off(event, handler)
Example
account.off('singin', showNotification)
Event | Description | Arguments |
---|---|---|
signup |
New user account created successfully | accountProperties with .session property |
signin |
Successfully signed in to an account | accountProperties with .session property |
signout |
Successfully signed out | accountProperties with .session property |
passwordreset |
Email with password reset token sent | |
unauthenticate |
Server responded with "unauthenticated" when checking session | |
reauthenticate |
Successfully signed in with the same username (useful when session has expired) | accountProperties with .session property |
update |
Successfully updated an account's properties | accountProperties with .session property |
// clear user’s local store signin and after signout
account.hook.before('signin', function (options) {
return localUserStore.clear()
})
account.hook.after('signout', function (options) {
return localUserStore.clear()
})
Hook | Arguments |
---|---|
signin |
options as they were passed into account.signIn(options) |
signout |
{} |
See before-after-hook for more information.
Hoodie comes with a list of built-in account requests, which can be disabled, overwritten or extended in hoodie-account-server
When a request succeeds, an event with the same name as the request type gets
emitted. For example, account.request({type: 'passwordreset', contact: 'pat@example.com')
triggers a passwordreset
event, with the requestProperties
passed as argument.
passwordreset |
Request a password reset token |
---|
Local setup
git clone https://github.com/hoodiehq/hoodie-account-client.git
cd hoodie-account-client
npm install
In Node.js
Run all tests and validate JavaScript Code Style using standard
npm test
To run only the tests
npm run test:node
To test hoodie-account-client in a browser you can link it into hoodie-account, which provides a dev-server:
git clone https://github.com/hoodiehq/hoodie-account.git
cd hoodie-account
npm install
npm link /path/to/hoodie-account-client
npm start
hoodie-account bundles hoodie-account-client on npm start
, so you need to restart hoodie-account to see your changes.
Have a look at the Hoodie project’s contribution guidelines. If you want to hang out you can join our Hoodie Community Chat.