apostrophe-passport works together with
passport-gitlab2 and similar passport strategy modules to let users log in to Apostrophe CMS sites via Google, Gitlab and other authentication providers. This feature is often called federation or single sign-on.
You need this module, plus the passport strategy module(s) of your choice:
npm install --save apostrophe-passport # Just an example, lots of passport modules will work npm install --save passport-gitlab2
Most modules that have "passport" in the name and let you log in via a third-party website will work.
// in app.js// YOU MUST CONFIGURE baseUrl. For local dev testing// you can set it to , for production// it must be realbaseUrl: ''modules:'apostrophe-passport':strategies:// gitlab login// You must npm install --save this module in your project firstmodule: 'passport-gitlab2'options:// Options for passport-gitlab2, see the documentation of that module,// you do not have to set callbackURLclientID: 'xxx'clientSecret: 'yyy'
Where do I
require the passport strategy?
You don't. Apostrophe does it for you. You pass its configuration in the
options key, and sometimes also the
authenticate key if it has options that must be passed to its
authenticate middleware, as with Google (you'll see this in its documentation).
How do users log in?
Type this command to print the URLs for login, and for the openauth callback URL:
node app apostrophe-passport:list-urls
You'll see something like:
These are the login URLs you may wish to link users to: /auth/gitlab/login These are the callback URLs you may need to configure on sites: http://localhost:3000/auth/gitlab/callback
So in this case, you'll want to add a login button to the
layout.html of your own site that simply links to:
That's all there is to it. When a user reaches this URL they are redirected to begin the authorization process with Gitlab, or the service of your choice.
Where do I get my
You get these from the website users will log in on, usually by adding an "app" to your profile or developer console. For Google you will need to create an application in the Google API console and authorize it to use the Google+ API service to access profile information (no, this does not mean users have to do anything with Google Plus). See the documentation of the passport strategy module you're using.
You will need to specify a
callbackURL when registering your "app." You can print that information via the same command line task we saw above:
node app apostrophe-passport:list-urls`
You can use a URL like
http://localhost:3000for testing but in production you must use your production URL. You cannot use an IP address for your callback URL, at least not with Google.
Google login, and creating users on the fly
By default, users are not created if they don't already exist on the site. If the user on the federated site (gitlab, in this example) is valid but the same username doesn't exist on the Apostrophe site, no login takes place. It's possible to change this.
Google login is a popular case where creating users on the fly can make sense as long as they are part of your email domain. Here's a working configuration for Google login. Note that you must first
npm install the
passport-google-oauth20 module for your project.
'apostrophe-passport':strategies:// google login via openauth// You must npm install --save this module in your project firstmodule: 'passport-google-oauth20'// Default is to match usernames, google has none, so match on emailsmatch: 'email'// IMPORTANT: accept only users with an email address at our companyemailDomain: 'mycompany.com'options:// options for passport-google-oauth20, see the documentation of// that module, you do not have to set callbackURLclientID: 'xxx'clientSecret: 'yyy'// Options that must be passed to the authenticate middlewareauthenticate:// minimum scopes for matching logins based on email addresses.// profile is absolutely required, you almost certainly want email tooscope: 'profile' 'email'// Presence of "create" key means we'll create users on the flycreate:// Presence of "group" means we'll add them to a group...group:// Called "google"...title: 'google'// With these Apostrophe permissions (admin can do ANYTHING, so be careful)permissions: 'admin'
"What is this
authenticate key about?" For whatever reason, the
passport-google-oauth20 module requires that some options be passed to passport's
authenticate middleware, rather than when configuring the strategy.
scope is one of these and it is required by Google.
"Do I have to pre-create the group users will be added to?" No, it will be created for you. Also, if you supply a
permissions property, it will always be refreshed to those permissions at restart. You might consider leaving that property off and manually setting the permissions via the groups editor.
Wait, how do permissions in Apostrophe work again?
A common question at this point. See managing permissions in Apostrophe.
Beefing up the "create" option: copying extra properties
The "create" option shown above will create a user with minimal information: first name, last name, full name, username, and email address (where available).
If you wish to import other fields from the profile object provided by the passport strategy, add an
import function to your configuration for that strategy. The
import function receives
(profile, user) and may copy properties from
user as it sees fit.
You may enable more than one strategy at the same time. Just configure them consecutively to the
strategies array. This means you can have login via Twitter, Google, etc. on the same site.
How should I map users on their site to users on my site?
It's really up to you. Usernames and emails are almost permanent, but people do change them and that can be problematic, especially if they are reused by someone else. (Protip: don't let people reuse email addresses or usernames within your organization. Just retire them.)
On the other hand, IDs are a pain to work with if you are creating users in advance and not using the
create feature of the module.
You can set the
match option for any strategy to one of the following choices:
Matches on the id of their profile as returned by the strategy module. This is most unique, however if you don't set
create, then you'll need to find out the ids of users in advance and populate them in your database. You could do that by adding a string field to your
addFields configuration for
To accommodate multiple strategies, If the strategy name is
googleId field of the suer. If the strategy name is
gitlab, the id needs to be in
gitlabId, and so on. If you are using the
create feature, these properties are automatically populated for you.
The strategy name and the npm module name are not quite the same thing. Look at the output of
node app apostrophe-passport:list-urls. The word that follows
/auth is the strategy name.
This will match on any email the authentication provider indicates they own, whether it is an array in the
.emails property of their profile containing objects with
.value properties (as with Google), an array of strings in
.emails, or just an
emails which has the same effect. Either way it will check all three cases.
The default. Users are matched based on having the same username.
A function of your choice
If you provide a function, it will receive the user's profile from the passport strategy, and must return a MongoDB criteria object matching the appropriate user. Do not worry about checking the
type properties, Apostrophe will handle that.
Locking down your site by email address domain name
You may wish to accept only users from one email domain, which is very handy if your company's email is hosted by Google (aka "G Suite"). For that, also set the
emailDomain option to the domain name you wish to allow. All others are rejected. This is very important if you are using the
Rejecting users for your own reasons
You can set your own policy for rejecting users by passing an
accept function for any strategy. This function takes the
profile object provided by the passport strategy and must return
true otherwise the user is not permitted to log in.
Disabling ordinary logins
"This is great, but I want to get rid of the regular
/login page." You can:
// in app.jsmodules:'apostrophe-passport':// As above; this is not where we disable local login...'apostrophe-login':// We disable it here, by configuring the built-in apostrophe-login` modulelocalLogin: false
The login page is powered by Passport's
localstrategy, which is added to Apostrophe by the standard
apostrophe-loginmodule. That's why we disable it there and not in
Overriding the error page
If login fails, for instance because you are matching on
username duplicates another account, or because a user is valid in Google but
emailDomain does not match, the
error.html template of the
apostrophe-passport module is rendered. By default, it works, but it's pretty ugly! You'll want to customize it to your project's needs.
Like other templates in Apostrophe, you can override this template by copying it to
lib/modules/apostrophe-passport/views/error.html in your project (do not modify the npm module itself). You can then extend your own layout template and so on, just as you have most likely already done for the 404 Not Found page or the
Frequently Asked Questions
"What about redirecting
/login to one of these fancy new strategies?"
You can do that. Once the login page is gone, it's possible for you to decide what happens at that URL. Use the apostrophe-redirects module to set it up through a nice UI, or add an Express route and a redirect in your own code.
"I tried this with [passport strategy module X] and it didn't work."
Feel free to open an issue but be sure to provide full specifics and a test project. Note that some strategies may not follow the standard practices this module is built upon. Those written by Jared Hanson, the author of Passport, or following his best practices should work well. You might want to test directly with the sample code provided with that strategy module first, to rule out problems with the module or with your configuration of it.