AngularJS module that adds user authentication to your app with UserApp. It supports protected/public routes, rerouting on login/logout, heartbeats for status checks, stores the session token in a cookie, directives for signup/login/logout, OAuth, etc.
UserApp is a user management API for web & mobile apps with the purpose to relieve developers from having to program logic for user authentication, sign-up, invoicing, feature/property/permission management, and more.
- Getting Started
- Accessing the logged in user
- Verify email address
- Reset password
- Access-controlling routes
- Loaders
- Heartbeats
- Back-end
- PhoneGap
- Services
- Directives
- Events
- Example
- Help
- License
Take the course on Codecademy
or
- Include the UserApp JavaScript library and this AngularJS module in your index.html:
<script src="https://app.userapp.io/js/userapp.client.js"></script>
<script src="https://app.userapp.io/js/angularjs.userapp.js"></script>
(You can also install the module with bower: $ bower install userapp-angular
)
- Add the
UserApp
module to your app's dependencies (app.js):
var app = angular.module('myApp', [..., 'UserApp']);
- Inject and initiate the service in your
run()
block (app.js) with your App Id:
app.run(function(user) {
user.init({ appId: 'YOUR_APP_ID' });
});
- Create routes + templates for login and signup, and use the directives to connect them to UserApp (examples: login.html and signup.html):
$routeProvider.when('/login', {templateUrl: 'partials/login.html'});
$routeProvider.when('/signup', {templateUrl: 'partials/signup.html'});
Note: If you are using ui-router, all you have to do is to create states instead of the routes above.
- Set
public
totrue
on the routes you want to make public. And setlogin
totrue
on the login route:
$routeProvider.when('/login', {templateUrl: 'partials/login.html', login: true});
$routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});
The .otherwise()
route should be set to where you want your users to be redirected after login. Example:
$routeProvider.otherwise({redirectTo: '/home'});
Note: If you are using ui-router, place the public
and login
flags inside data
instead.
- Add a log out link:
<a href="#" ua-logout>Log Out</a>
(Ends the session and redirects to the login route)
- Hide elements that should only be visible when logged in:
<div ng-show="user.authenticated">Welcome!</div>
- Use the
user
object to access properties on the logged in user:
<div ng-show="user.authenticated">Welcome {{ user.first_name }}!</div>
From templates you only use user
, but to access the logged in user from controllers, use user.current
or the promise user.getCurrent()
.
- Read this documention and the UserApp Documentation to learn how to use the full API!
The logged in user has the same fields as the user profile in UserApp. See below how to access it.
From templates
Access the logged in user profile using the user
object.
<p>{{ user.first_name }}</p>
From controllers, services, etc.
To access the logged in user from your controllers, services, etc., use the current
property on the user
service like this:
var currentUser = user.current;
You can also use a promise to ensure that the user is loaded when accessing it, as the user might not have been loaded when your component loads. However, the user will always be loaded when your controller loads (see requirements for ui-router below).
user.getCurrent().then(function(currentUser) {
console.log(currentUser.first_name);
});
ui-router requires the resolve
property to be present on the states that should wait for the user profile to load. An empty object is enough:
resolve: {}
To force your new sign-ups to verify their email address, you first need to activate the Email Add-on in UserApp, and then configure the Verification Email.
When this is done, you need to modify your sign up page to show a message to the user after they have signed up. This message should tell them to check their inbox for a verification email.
When a verification email has been sent, the variable verificationEmailSent
will be set to true
, so just use ng-show
to show/hide the message:
<p ng-show="verificationEmailSent">An email has been sent to your inbox. Click on the link to verify your account.</p>
This email should be configured to include a link to a route that you will set up with UserApp by adding the verify_email
flag:
$routeProvider.when('/verify-email', {templateUrl: 'partials/verify-email.html', verify_email: true});
Note: Don't provide this route with a controller, the module will automatically do that. If you want to handle errors, check if the usual error
object is set.
The template partials/verify-email.html
could look something like this:
<div ng-show="loading">
Verifying your email address, please wait...
</div>
<div ng-show="!loading">
Your email address has been verified, <a href="#/login">click here</a> to log in.
</div>
The variable loading
is set to true
while the email token is being verified against UserApp.
Now, log in into UserApp and edit the Verification Email to include a link to http://yourapp.com/#/verify-email?email_token={{email_token}}
,
where "http://yourapp.com" should be replaced with your own address (e.g. "http://localhost").
And that should do it! Try to sign up with your own email address and check that the flow works as it should.
To implement a reset-password functionality together with UserApp's Email Add-on, first make sure that the add-on is enabled and that you have enabled the reset-password email. (Log in->Add-ons->Email).
Then create a new route that will be used for the reset-password form:
$routeProvider.when('/reset-password', {templateUrl: 'partials/reset-password.html', public: true});
Note: Set the public
flag to true
so it will be accessible without logging in.
The template partials/reset-password.html
should consist of a form with an input box for login/username, and a submit button. Something like this:
<form ua-reset-password ng-show="!emailSent">
<input name="login" placeholder="Username"><br>
<button type="submit">Send email</button>
<p ng-show="error">{{ error.message }}</p>
</form>
<p ng-show="emailSent">An email has been sent to your inbox. Click on the link to set a new password.</p>
The directive ua-reset-password
connects the form to UserApp, with the input named login
as the login name. When an error occurs, the error
object will contain more information about it.
When the email has been sent, the variable emailSent
is set to true
. Use this to show a friendly message to the user, like in the example above.
Next step is to set up the route which the user will enter the new password. Create a new route with the set_password
flag set to true
, like this:
$routeProvider.when('/set-password', {templateUrl: 'partials/set-password.html', set_password: true});
The template partials/set-password.html
should consist of a form with an input box for the new password, and a submit button:
<form ua-set-password ng-show="!passwordSaved">
<input name="new_password" type="password" placeholder="New password"><br>
<button type="submit">Save password</button>
<p ng-show="error">{{ error.message }}</p>
</form>
<p ng-show="passwordSaved">Your new password has been saved, now <a href="#/login">log in</a>!</p>
Attach the form to UserApp with the ua-set-password
directive and an input named new_password
. Use the error
object to show errors. When the password has been saved, the variable passwordSaved
will be set to true
.
And last, log into UserApp and include a link to the set-password form in the Reset Password email, so something like this: http://yourapp.com/#/set-password?password_token={{password_token}}
, where "http://yourapp.com" should be replaced with your own address (e.g. "http://localhost").
Routes/states can be declared as public by setting the public
property for the route to true
:
$routeProvider.when('/home', { public: true });
or when using UI router:
$stateProvider.state('home', { data: { public: true } });
The login
route/state, the verify_email
route/state, and the set_password
route/state are considered public by default.
If the user is not signed in and accesses a non-public route, the route/state change is prevented and the authenticationRequiredHandler
is invoked. The default handler transitions to the login
route. Another handler can be installed like this:
user.onAuthenticationRequired(function(route, stateParams) {
// open login popup, do transition, ...
});
For the Angular router the target route is passed to the handler. For the UI router, the target state and the target state parameters are passed.
To add required permissions to a route, use the hasPermission
property and specify all the permissions as an array, like this:
$routeProvider.when('/admin', { templateUrl: 'partials/admin.html', hasPermission: ['admin'] });
or as a string, like this:
$routeProvider.when('/admin', { templateUrl: 'partials/admin.html', hasPermission: 'admin' });
For a more general authorization check, use the authCheck
property and specify a function that takes the currently logged in user and returns true
if access to this user should be allowed and false
if access shall be denied.
$routeProvider.when('/admin', { templateUrl: 'partials/admin.html', authCheck: function(user) {
return user.properties['abc'] === 'def'
}});
If the UI router is used, the state parameters are passed as a second parameter:
$stateProvider.state('admin', { data: { public: false, authCheck: function(user, params) {
return user.properties['orgId'] === params.id
}}});
If access is denied to the logged in user (either because a required permission was not found or authCheck
returned false), the route/state change is prevented and the authorizationDeniedHandler
is invoked. The default handler redirects to the default route. Another handler can be installed like this:
user.onAccessDenied(function(user, route, stateParams) {
// show popup, do transition, ...
});
For the Angular router the target route is passed as second parameter to the handler. For the UI router, the target state and the target state parameters are passed as parameters two and three.
After a successful login, the default behavior is to transition to the default route. To change this behavior, override the authenticationSuccessHandler
like this:
user.onAuthenticationSuccess(function() {
// hide popup, do transition, ...
});
All directives sets the scope variable loading
to true
while it's doing work in the background. This way you could show a loader animation while waiting for the UserApp API to respond. Here's an example with the login form:
<form ua-login>
<input name="login" placeholder="Username"><br>
<input name="password" placeholder="Password" type="password"><br>
<button type="submit">
<span ng-show="!loading">Log In</span>
<img ng-show="loading" src="https://app.userapp.io/img/ajax-loader-transparent.gif">
</button>
<p ng-show="error">{{ error.message }}</p>
</form>
The AngularJS module pings the UserApp API with a constant interval to check for status changes and the same time keep the session alive.
If you want to change the interval these heartbeats are made, or turn them off completely, just set the option heartbeatInterval
to 0
.
The interval is specified in milliseconds and the minimum value is 10 seconds (10000 ms). The default is 20 seconds.
user.init({
appId: 'YOUR_APP_ID',
heartbeatInterval: 0
});
Since AngularJS is a front-end framework, all authentication with this module is only done on the client-side, with direct communication with UserApp.
To authorize to your back-end API, you need to provide the session token that was created at login. This token can then be validated against UserApp on the server-side to ensure that the user is authenticated.
If your API/back-end is on the same domain as your Angular app, you can simply get the token from the cookie named ua_session_token
. If it's not on the same domain, you need to manually provide it with your back-end requests. One solution is to include it with your GET/POST parameters. Another is to use the Authorization header.
Use the token()
method on the user
service to obtain the token.
var token = user.token();
An easy way to add the token to all your requests is to add it as a default header. By listening on the user.login
and user.logout
events we can set the header accordingly:
$rootScope.$on('user.login', function() {
$http.defaults.headers.common.Authorization = 'Basic ' + btoa(':' + user.token());
});
$rootScope.$on('user.logout', function() {
$http.defaults.headers.common.Authorization = null;
});
Please note that the btoa()
function may not be supported by all browsers.
On the back-end, use UserApp's token.heartbeat() or user.get() to verify that the token is valid. The result should then be cached to reduce round-trips to UserApp.
This module works perfectly out of the box with PhoneGap. But if you want persistent sessions (like the Facebook, Twitter, and Instagram apps has), you need to include userapp-phonegap into your project. It will automatically extend the AngularJS module with functionality that sets up persistent sessions.
The main service with all session handling etc.
-
user.init(config)
Initiate the service with your App Id.
user.init({ appId: 'YOUR_APP_ID' });
Another option is the
heartbeatInterval
, documented here. -
user.status()
Returns the status of the session:
{ authenticated: false }
-
user.appId([value])
Sets and gets the App Id.
-
user.token([value])
Sets and gets the session token (stored in a cookie).
-
user.current
The logged in user. See User documentation for more info. Note: This is not a function.
-
user.getCurrent()
Returns a promise to the logged in user (see above).
user.getCurrent().then(function(currentUser) { console.log(currentUser.user_id); });
-
user.signup(user[, callback])
Sign up a user, log in, and redirect to default route.
user.signup({ login: 'timothy', email: 'timothy.johansson@userapp.io', password: 't1m0thy' }, function(error, result) {});
-
user.login(user[, callback])
Log in a user and redirect to default route.
user.login({ login: 'timothy', password: 't1m0thy' }, function(error, result) {});
-
user.logout([callback])
Log out the logged in user and redirect to the log in route.
user.logout(function(error, result) {});
-
user.verifyEmail(emailToken[, callback])
Verifies an email address using an email token. Should be used together with the Email Add-on.
user.verifyEmail('EMAIL_TOKEN', function(error, result) {});
-
user.resetPassword(user[, callback])
Use this together with the Email Add-on to send a reset-password email to the user.
user.resetPassword({ login: 'timothy' }, function(error, result) {});
-
user.setPassword(passwordToken, newPassword[, callback])
Sets a new password using a password token.
user.setPassword('PASSWORD_TOKEN', 'secretPassw0rd', function(error, result) {});
-
user.hasPermission(permissions)
Returns
true
if the user has all the permissions in the string or arraypermissions
. Else it returnsfalse
.var result = user.hasPermission('edit'); var result = user.hasPermission(['edit', 'post']);
-
user.hasFeature(features)
Returns
true
if the user has all the features in the string or arrayfeatures
. Else it returnsfalse
.var result = user.hasFeature('editor'); var result = user.hasFeature(['editor', 'another_feature']);
Exposes the full UserApp API with the JavaScript library.
-
ua-login
Add this to a form tag to attach it to the
user.login()
function. Theerror
object will be set when an error occurs.<form ua-login> <input name="login" placeholder="Username"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Log In</button> <p ng-show="error">{{ error.message }}</p> </form>
-
ua-logout
Add this to a log out link to attach it to the
user.logout()
function.<a href="#" ua-logout>Log Out</a>
-
ua-signup
Add this to a form tag to attach it to the
user.signup()
function. Use theerror
object to show an message if an error occurs. Useua-is-email
on the login input to specify that login is the same as email. All input field names must reflect the user's properties.<form ua-signup> <input name="first_name" placeholder="Name"><br> <input name="login" ua-is-email placeholder="Email"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Create Account</button> <p ng-show="error">{{ error.message }}</p> </form>
To set custom properties on the user at the signup, name the custom fields
properties.[name]
. For example if you have a property calledage
, create an input like this:<input name="properties.age" placeholder="Age">
Note: If you have activated the Email Add-on and the Verification Email, the user won't be logged in after the sign up. Instead, the variable
verificationEmailSent
will be set totrue
so you could display a message to the user asking them to check the inbox. -
ua-reset-password
Add this to a form tag to attach it to the
user.resetPassword()
function. Use theerror
object to show an message if an error occurs. The form must have an input namedlogin
. When the email has been sent out, the variableemailSent
will be set totrue
. This directive can only be used together with the Email Add-on to send reset-password email.<form ua-reset-password ng-show="!emailSent"> <input name="login" placeholder="Username"><br> <button type="submit">Send email</button> <p ng-show="error">{{ error.message }}</p> </form> <p ng-show="emailSent">An email has been sent to your inbox. Click on the link to set a new password.</p>
-
ua-set-password
Add this to a form tag to attach it to the
user.setPassword()
function (i.e. the API methoduser.changePassword()
with the parameterpassword_token
). Use theerror
object to show an message if an error occurs. The form must have an input namednew_password
. When the password has been saved, the variablepasswordSaved
will be set totrue
.<form ua-set-password ng-show="!passwordSaved"> <input name="new_password" type="password" placeholder="New password"><br> <button type="submit">Save</button> <p ng-show="error">{{ error.message }}</p> </form> <p ng-show="passwordSaved">Your new password has been saved, now <a href="#/login">log in</a>!</p>
-
ua-oauth-link
Add this to a link tag in order to authenticate using an OAuth provider. The value should be an OAuth provider id such as
google
,github
,facebook
orlinkedin
. Additionally: Use theerror
object to show an message if an error occurs. Useua-oauth-scopes
to specify OAuth scopes to request by provider. The scopes must be a comma-separated list of scopes, i.e.user,user:email
. Useua-oauth-redirect-uri
to explicitly specify the URI to be redirected to after provider has performed authentication. If not specified, the default URI will be/#/oauth/callback/
.<a href="" ua-oauth-link="google">Log in with Google</a>
-
ua-has-permission="permissions"
Add this to an element to attach it to the
user.hasPermission()
function. The element will be hidden if not all permissions are true. Multiple permissions are separated with whitespace.<a href="#" ua-has-permission="edit">Edit Post</a>
-
ua-has-feature="features"
Add this to an element to attach it to the
user.hasFeature()
function. The element will be hidden if not all features are true. Multiple features are separated with whitespace.<a href="#" ua-has-feature="fancy_feature">Go to Fancy Feature...</a>
-
user.error
Event triggered when an error occurs.
$rootScope.$on('user.error', function(sender, error) { console.log(error.message); });
-
user.login
Event triggered when user logs in.
$rootScope.$on('user.login', function() { console.log(user.current); });
-
user.logout
Event triggered when user logs out.
$rootScope.$on('user.logout', function() { console.log('Bye!'); });
See example/ for a demo app based on angular-seed.
Contact us via email at support@userapp.io or visit our support center. You can also see the UserApp documentation for more information.
MIT, see LICENSE.