-
Posts
36,220 -
Joined
-
Last visited
-
Days Won
114
Content Type
Downloads
Release Notes
IPS4 Guides
IPS4 Developer Documentation
Invision Community Blog
Development Blog
Deprecation Tracker
Providers Directory
Projects
Release Notes v5
Invision Community 5 Bug Tracker
Forums
Events
Store
Gallery
Everything posted by Mark
-
4.4: Recurring PayPal Payments and more with Braintree and Commerce
Mark posted a blog entry in Invision Community
Braintree is a payment gateway provided by PayPal which provides some great additional features for PayPal transactions including a significantly improved recurring payments model. We are delighted to be bringing full support for Braintree for Commerce in Invision Community 4.4. What is Braintree? Braintree is a payment gateway provided by PayPal which supports taking payments by credit cards (including Apple Pay and Google Pay) and Venmo as well as PayPal, providing a good option for communities wanting to use a single payment gateway, and also brings improved functionality for recurring PayPal transactions. For PayPal transactions, there are no additional fees and the checkout experience uses the normal PayPal experience your customers are used to. Recurring PayPal Improvements Recurring payments / Billing Agreements in PayPal have up until now been initiated by PayPal. Invision Community tells PayPal what the renewal terms of a purchase are, but then it's up to PayPal to take that payment and notify your community when it succeeds (or fails). This comes with a number of limitations and problems. It makes it difficult for you as an admin to modify an existing purchase or for the customer to upgrade/downgrade. It also means the customer has to create separate Billing Agreements for each purchase. Most significantly though, it means if there is a delay in receiving the payment (such as an expired card) it is sometimes unclear what should happen on your community's end, and how it can be resolved if/when the payment is received. Other payment gateways work the other way around. When a customer pays by card, for example, they have the option of storing their card details. Later, if they make another purchase or a renewal invoice is generated, Invision Community can tell the gateway to recharge the same card - and if it fails, allow the customer to provide an alternative payment method. This allow both you and your customers to have much greater control, and is much more reliable. Braintree resolves this by allowing customers when paying with PayPal to save their PayPal account in the same way they would save a credit card on file. When paying with PayPal, users will see a simple checkbox which, if checked, will allow future payments to be taken with PayPal automatically. Storing PayPal Accounts for Recurring Payments Other Features In addition to an improved checkout experience, our integration with Braintree supports: Taking payments by Credit Card, including 3DSecure checking and the ability for customer to store card details on file. Braintree uses a fully PCI-compliant method of taking card details in a way that ensures the card information never reaches your server. Apple Pay and Google Pay Venmo, which also allows storing accounts in the same way as PayPal accounts. Offering PayPal Credit Handling chargebacks/disputes Support for Braintree's Advanced Fraud Tools A Disputed PayPal Transaction Existing Setups and Upgrading The existing PayPal gateway will continue to be available for basic PayPal integration, and your existing set up will continue to work exactly as it does now after upgrading. If you are using PayPal, especially if you are using Billing Agreements, we strongly recommend switching to Braintree after upgrading. While it isn't possible to convert existing Billing Agreements, you can allow existing ones to continue to work and use Braintree for new purchases. Please note that while existing setups will work fine, from 4.4 it will no longer be possible to set up a new PayPal method with either Billing Agreements, or to take payments by card, as PayPal has deprecated the API this was using in favour of Braintree and it can no longer be enabled on new accounts. As mentioned though, this does not affect any existing setups, which, if you do not switch to Braintree, will continue to work as they do now. This blog is about our upcoming release Invision Community 4.4. -
To clarify since @Joel R mentioned me specifically... 😂 We will be sticking with CKEditor 4 for a little while. While we will presumably move to CKEditor 5 some time in the future, it is currently still very new and maturing (when Joel asked me, it was before 5.11.2.0 was released which is when they re-added paste from word). But most importantly, to move would require a lot of development time (to upgrade our custom plugins) for what will be, to the end-user, very little change. And since CKEditor plans to continue releasing updates to version 4 for the foreseeable future we're not missing out on bug fixes or security patches. Obviously if you're experiencing issues, please submit a support ticket and we can look into that - if you're not seeing the same problems on CKEditor's demo, the problem is likely our end and so it's probable that moving to CKEditor 5 wouldn't resolve it.
-
We haven't used salted md5s since v4 😉 We use bcrypt.
-
Allowing your customers to find exactly what they need as fast as possible will no doubt increase sales. A good number of our customers use Commerce to sell physical items. Until now, it's always been a little tricky to set up the store to allow customers to drill down into specific items within the store. In Invision Community 4.4, the sidebar in the store now includes filter options to help customers find the product they're looking for. Using the filter sidebar Administrators can set up whatever filters they like for each product. In this video above, you can see we have set up filters for color and price. You can set these filters up in the AdminCP by simply specifying each possible option: Creating a custom filter Once the filters have been set up, you can then add each filter to the categories it applies to (so you can have different filters for different categories) and when editing any product you can specify as many values for each filter as is appropriate (for example, if you have a color filter, you can choose multiple colors if the product allows the customer to choose a color, or if the product has multiple colors). Choosing the filter values when creating/editing a product In addition to these custom filters, you will also see filters for price (you can set appropriate bands for each category), rating, and stock level. Other Commerce Improvements In addition, we also have a few more features new to Commerce in 4.4: There are new sidebar blocks for best selling products, latest products, product reviews and a featured product. When sending a bulk mail, you can target recipients by the total amount they have spent. Categories with no products in them are hidden automatically in the store. Notification emails sent to customers to let them know their purchase will expire soon (including if they will be automatically charged) have been improved to show more clearly what will happen. When viewing a customer page in the AdminCP, active purchases are separated from expired and cancelled purchases to make it easier to discern which are active. Custom field values are now included on printed invoices. When filtering support requests in the AdminCP, you can now choose "more than" or "less than" for all time-based filter options. When using stock actions to reply to support requests, the stock reply can be incorporated into the staff member's default reply content rather than overwriting it. Invoices in the AdminCP can now be filtered by status. This blog is part of our series introducing new features for Invision Community 4.4.
-
4.4: Increase visitor registrations with Post Before Registering
Mark posted a blog entry in Invision Community
It's very easy to focus on a single metric to gauge the success of your community. It's very common for community owners to look at page hits and determine if their SEO and marketing efforts have paid off. Getting traffic to your site is only half the equation though. The most valuable metric is how many casual visitors you're converting to engaged members. Invision Community already makes it easy for guests to sign up using external services such as Facebook, Twitter and Google. However, there has to be a conscious decision to click that sign-up button. For some, this may be a barrier too many. Invision Community 4.4 reduces this barrier by allowing guests to create a post to a topic they want to engage with. Once they have posted, they are asked to simply complete their registration. They are more likely to do this now they have invested in your community. This will be incredibly valuable when you consider how much traffic a forum receives from inbound Google searches. With Post Before Registering, you'll increase your chances of turning that inbound lead into a registered member contributing to your site. Let me take you through the feature and show you how it works. When browsing the community guests will see the ability to submit a post, with an explanation that they can post now and complete registration later. The only thing they have to provide in addition to their post is an email address. Posting as a guest This works in any application for new content (topics, Gallery images, etc.) as well as comments and reviews. It will only show when a newly registered member would be able to post in that area - for example, it will not show in a forum that only administrators can post in. After submitting the post, the post will not be visible to any user, but the user will immediately be redirected to the registration form with an explanation to complete the registration. The email address they provided will already be filled in. Registration form after posting as a guest At this point, the user can either fill in the registration form, or use a social sign in method like Facebook or Twitter to create an account. After the account has been created, and validation has been completed if necessary, their post will automatically be made visible just as if they had registered and then posted. If the user abandons the registration after they've submitted their post, an email will be sent to them to remind them to complete the registration. Email reminding user to finish registering Some Notes Invision Community already has a feature that allows guests to post as guests without registration if granted permission. That feature has not been removed and so if you already allow guests to post, the behaviour will not change. This new feature is only available when a guest can't post in a given area, but a member would be able to. The entire feature can also be turned off if undesired. If the area the guest is posting in requires moderator approval, or newly registered members require approval of new posts, the post will enter the moderation queue as normal once their account has been created. Third party applications will require minor updates to support this feature. Once your casual visitor has invested time in your community by crafting a post, they are much more likely to finish the registration to get it posted. If you have set up external log in methods, then registration only takes a few more clicks. This blog is part of our series introducing new features for Invision Community 4.4. -
Do you recall that scene in Harry Potter where young Harry is sitting in his Uncle’s living room when hundreds of letters from Hogwarts burst through the fireplace, filling the room? Sometimes, when you log into the administrator’s control panel, it can feel a bit like that. As the administration control panel has evolved, there has been more of a need to display notifications, alerts and warnings to the administrators. There are several things which may require an administrator's attention which may show a notice on the AdminCP dashboard, a banner on the community, or send an email. For example: When a new version of Invision Community is released. A new member registers and requires administrator validation. A configuration issue is detected, for example if dangerous PHP functions are enabled on the server. There are items Commerce which require manual action, such as transactions pending manual approval or items to be shipped. Up until now, each such area would manage how these notifications show and are sent independently. In 4.4 we have introduced a new section of the AdminCP which shows all things which require administrator attention in one place, easily accessible from any AdminCP page. AdminCP Notification Menu Clicking on any of these notifications will take you to the relevant area of the AdminCP, or there is also a full-screen Notification Center which allows you to quickly take common actions such as approving members. AdminCP Notification Center While the best approach is to take the appropriate action (which will automatically dismiss the notification) so you always have an empty Notification Center, most notification types can be hidden, either temporarily on a per-notification basis by clicking the cross in the top-right, or administrators can hide all notifications of a certain type from their individual settings. Administrators can also choose which type of notifications to receive an email notification about. Notification Settings Each notification has a severity indicated by the coloured bar on the side and certain notifications can also show banners either across the AdminCP, or also on the front-end (to administrators). Notifications group automatically (so for example, if there are 5 members pending approval, you will see 1 notification rather than 5 separate ones) and where appropriate each administrator can choose if they want to receive a single email, or a separate email with each occurrence. Now you won't miss an invitation to Hogwarts, or anything important again. This is a blog about our upcoming Invision Community 4.4 release, due later this year.
-
Version 4.3.5 is a small maintenance update to fix issues reported since 4.3.4.
-
Added a filter to view members that have opt-in for bulk mail in the ACP, and an option to opt-out those members Bug fixes
-
New features for GDPR compliance: New feature for administrators to download an XML file of all personal information held. New setting to automatically prune IP address records. New option when deleting a member to anonymize content submitted by them. New setting to automatically add links to privacy policies of integrated third party services such as Google Analytics or Facebook Pixel to your privacy policy if they are enabled. Fixes an issue where Calendar events submitted in different timezones to the user may show at the wrong time. Other minor bug fixes and improvements. Learn more about GDPR compliance features in this release
-
Version 4.3.2 is a small maintenance update to fix issues reported since 4.3.1, including: Promotes non-functional when "Our Picks" disabled. Various emoji fixes, including skintones and mobile issues. Online stats. Numerous IE11 fixes. PayPal billing agreements failing due to lack of address.
-
This is a maintenance to release to the 4.2 series address security issues. As we prepare for our next large release, version 4.3, we do large security audits. We decided to apply those security enhancements to the 4.2 series so you can get them now if you prefer to not upgrade to 4.3 yet. We would like to thank @newbie LAC for his assistance.
-
Handling Account Changes You may want to change the display name, email address and/or password in your Login Handler's database when the user changes those details locally. This is especially likely for Username/Password Handlers. There are lots of possible combinations of login handlers. A community might be using your login handler in combination with many other different handlers, or they might be using only your login handler and even have disabled the standard login handler. The two Username/Password Handlers in Invision Community (MySQL database and LDAP) both provide settings to allow the administrator to control if this syncing should be done and so it is recommended that you do the same (you can copy the code for creating these settings). You will implement several methods. Here is some sample code for the methods you need to implement, including the code for creating the settings: /** * ACP Settings Form * * @param string $url URL to redirect user to after successful submission * @return array List of settings to save - settings will be stored to core_login_methods.login_settings DB field * @code return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... ); * @endcode */ public function acpForm() { $return = array(); $return[] = 'account_management_settings'; $return['sync_name_changes'] = new \IPS\Helpers\Form\Radio( 'login_sync_name_changes', isset( $this->settings['sync_name_changes'] ) ? $this->settings['sync_name_changes'] : 1, FALSE, array( 'options' => array( 1 => 'login_sync_changes_yes', 0 => 'login_sync_changes_no', ) ) ); if ( \IPS\Settings::i()->allow_email_changes == 'normal' ) { $return['sync_email_changes'] = new \IPS\Helpers\Form\Radio( 'login_sync_email_changes', isset( $this->settings['sync_email_changes'] ) ? $this->settings['sync_email_changes'] : 1, FALSE, array( 'options' => array( 1 => 'login_sync_changes_yes', 0 => 'login_sync_changes_no', ) ) ); } if ( \IPS\Settings::i()->allow_password_changes == 'normal' ) { $return['sync_password_changes'] = new \IPS\Helpers\Form\Radio( 'login_sync_password_changes', isset( $this->settings['sync_password_changes'] ) ? $this->settings['sync_password_changes'] : 1, FALSE, array( 'options' => array( 1 => 'login_sync_changes_yes', 0 => 'login_sync_password_changes_no', ) ) ); } return $return; } /** * Can this handler process a password change for a member? * * @return bool */ public function canChangePassword( \IPS\Member $member ) { if ( !isset( $this->settings['sync_password_changes'] ) or $this->settings['sync_password_changes'] ) { // NOTE: This looks up if there is a core_login_links record for the member (i.e. if they have signed in with // your login handler before). return $this->canProcess( $member ); } return FALSE; } /** * Change Email Address * * @param \IPS\Member $member The member * @param string $oldEmail Old Email Address * @param string $newEmail New Email Address * @return void * @throws \IPS\Db\Exception */ public function changeEmail( \IPS\Member $member, $oldEmail, $newEmail ) { if ( !isset( $this->settings['sync_email_changes'] ) or $this->settings['sync_email_changes'] ) { // @todo - actually change the email in the Login Handler database } } /** * Change Password * * @param \IPS\Member $member The member * @param string $newPassword New Password * @return void * @throws \IPS\Db\Exception */ public function changePassword( \IPS\Member $member, $newPassword ) { if ( !isset( $this->settings['sync_password_changes'] ) or $this->settings['sync_password_changes'] ) { // @todo - actually change the password in the Login Handler database } } /** * Change Username * * @param \IPS\Member $member The member * @param string $oldUsername Old Username * @param string $newUsername New Username * @return void * @throws \IPS\Db\Exception */ public function changeUsername( \IPS\Member $member, $oldUsername, $newUsername ) { if ( !isset( $this->settings['sync_name_changes'] ) or $this->settings['sync_name_changes'] ) { // @todo - actually change the username in the Login Handler database } } Checking if Email or Username Is In Use You may want to prevent users using email addresses or usernames which exist in your Login Handler's database even before that user has created their local account. This is especially likely for Username/Password Handlers. To do this you will implement several methods. Here is are the skeletons for the methods you need to implement. They should return a boolean value. /** * Email is in use? * Used when registering or changing an email address to check the new one is available * * @param string $email Email Address * @param \IPS\Member|NULL $eclude Member to exclude * @return bool|NULL Boolean indicates if email is in use (TRUE means is in use and thus not registerable) or NULL if this handler does not support such an API */ public function emailIsInUse( $email, \IPS\Member $exclude=NULL ) { return NULL; } /** * Username is in use? * Used when registering or changing an username to check the new one is available * * @param string $username Username * @param \IPS\Member|NULL $eclude Member to exclude * @return bool|NULL Boolean indicates if username is in use (TRUE means is in use and thus not registerable) or NULL if this handler does not support such an API */ public function usernameIsInUse( $username, \IPS\Member $exclude=NULL ) { return NULL; } Handling Forgotten Passwords If a user uses the "Forgot Password" tool, you may want to redirect them to your site if they enter a email address which has been used, or could be used, by your Login Handler. This is especially likely for Username/Password Handlers. First, you should implement the emailIsInUse() method described above first. Then you will need to implement this method, returning an \IPS\Http\Url object: /** * Forgot Password URL * * @return \IPS\Http\Url|NULL */ public function forgotPasswordUrl() { return NULL; } Showing a Logo on Device Information Page When viewing their Recently Used Devices, Invision Community will indicate what Login Method was used to assist the user in identifying if they performed the log in. You can optionally provide a logo to display alongside the Login Method name on this screen. Simply implement the logoForDeviceInformation() method, returning an \IPS\Http\Url object: /** * Get logo to display in information about logins with this method * Returns NULL for methods where it is not necessary to indicate the method, e..g Standard * * @return \IPS\Http\Url */ public function logoForDeviceInformation() { return NULL; }
-
Users may want to sync some of their details from your login handler's database to the community. The data that can be synced is: Display name Email address Profile photo Cover photo Status updates For example, users who have logged in with Facebook can use their Facebook profile photo on the community, and optionally update the email address used on the community if they change it on Facebook. Your login handler can provide this syncing too. Even if the user chooses to not sync this data, it is also used in certain other areas, for example, when viewing a member in the AdminCP, it will show their display name and profile photo for all of the login handlers they are logged in with, even if they are not being synced. Step 1: Implement Methods For Getting Data There are several methods to implement. You should implement all of the methods that your login handler can provide the data for and leave the others unimplemented (for example, if your login handler doesn't have profile photos, you can skip that method). Here is are the skeletons for the methods you need to implement: /** * Get user's identifier (doesn't have to be a number) * May return NULL if server doesn't support this * * @param \IPS\Member $member Member * @return string|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userId( \IPS\Member $member ) { return NULL; } /** * Get user's profile photo * May return NULL if server doesn't support this * * @param \IPS\Member $member Member * @return \IPS\Http\Url|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userProfilePhoto( \IPS\Member $member ) { return NULL; } /** * Get user's profile name * May return NULL if server doesn't support this * * @param \IPS\Member $member Member * @return string|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userProfileName( \IPS\Member $member ) { return NULL; } /** * Get user's email address * May return NULL if server doesn't support this * * @param \IPS\Member $member Member * @return string|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userEmail( \IPS\Member $member ) { return NULL; } /** * Get user's cover photo * May return NULL if server doesn't support this * * @param \IPS\Member $member Member * @return \IPS\Http\Url|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userCoverPhoto( \IPS\Member $member ) { return NULL; } /** * Get user's statuses since a particular date * * @param \IPS\Member $member Member * @param \IPS\DateTime|NULL $since Date/Time to get statuses since then, or NULL to get the latest one * @return array * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userStatuses( \IPS\Member $member, \IPS\DateTime $since = NULL ) { return array(); } /** * Get link to user's remote profile * May return NULL if server doesn't support this * * @param string $identifier The ID Nnumber/string from remote service * @param string $username The username from remote service * @return \IPS\Http\Url|NULL * @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate * @throws \DomainException General error where it is safe to show a message to the user * @throws \RuntimeException Unexpected error from service */ public function userLink( $identifier, $username ) { return NULL; } Step 2: Show Your Login Handler in the Account Settings In order to configure which syncing options are available, a section will need to be added to the Account Settings page for your Login Handler. The convention that all default Login Handlers follow is to allow the admin the option to always show a section (Invision Community will automatically create a page that allows users to log in with the handler linking their accounts if they're not already logged in with it), only show a section if the user has already logged in with that method, or not show one at all (which won't allow them to sync their details). To follow this convention you just need to add a setting for that - the code to check its value is already present: /** * ACP Settings Form * * @param string $url URL to redirect user to after successful submission * @return array List of settings to save - settings will be stored to core_login_methods.login_settings DB field * @code return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... ); * @endcode */ public function acpForm() { $return = array(); // ... any other settings you already have ... $return['show_in_ucp'] = new \IPS\Helpers\Form\Radio( 'login_handler_show_in_ucp', isset( $this->settings['show_in_ucp'] ) ? $this->settings['show_in_ucp'] : 'disabled', FALSE, array( 'options' => array( 'always' => 'login_handler_show_in_ucp_always', 'loggedin' => 'login_handler_show_in_ucp_loggedin', 'disabled' => 'login_handler_show_in_ucp_disabled' ), ) ); return $return; } Alternatively you can override the showInUcp() method to implement other logic to determine if your login handler should show: /** * Show in Account Settings? * * @param \IPS\Member|NULL $member The member, or NULL for if it should show generally * @return bool */ public function showInUcp( \IPS\Member $member = NULL ) { // ... } You should also implement the logoForUcp() method which determines the logo to use alongside the link to your Login Handler's area of the Account Settings. You can return an \IPS\Http\Url object, or a string with a Fontawesome icon name: /** * Get logo to display in user cp sidebar * * @return \IPS\Http\Url|string */ public function logoForUcp() { return 'sign-in'; } Step 3: Add Syncing Options Finally you need to implement a syncOptions() method which returns the things which can be synced. The convention is to offer profile photo and cover photo syncing automatically if your Login Handler supports it, and have settings to control if email and username syncing is offered. To do this, you might implement settings like this: /** * ACP Settings Form * * @param string $url URL to redirect user to after successful submission * @return array List of settings to save - settings will be stored to core_login_methods.login_settings DB field * @code return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... ); * @endcode */ public function acpForm() { $return = array(); // ... any other settings you already have ... $return['show_in_ucp'] = new \IPS\Helpers\Form\Radio( 'login_handler_show_in_ucp', isset( $this->settings['show_in_ucp'] ) ? $this->settings['show_in_ucp'] : 'disabled', FALSE, array( 'options' => array( 'always' => 'login_handler_show_in_ucp_always', 'loggedin' => 'login_handler_show_in_ucp_loggedin', 'disabled' => 'login_handler_show_in_ucp_disabled' ), 'toggles' => array( 'always' => array( 'login_update_name_changes_inc_optional', 'login_update_email_changes_inc_optional' ), 'loggedin' => array( 'login_update_name_changes_inc_optional', 'login_update_email_changes_inc_optional' ), 'disabled' => array( 'login_update_name_changes_no_optional', 'login_update_email_changes_no_optional' ), ) ) ); $return['update_name_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_inc_optional', isset( $this->settings['update_name_changes'] ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array( 'force' => 'login_update_changes_yes', 'optional' => 'login_update_changes_optional', 'disabled' => 'login_update_changes_no', ) ), NULL, NULL, NULL, 'login_update_name_changes_inc_optional' ); $return['update_name_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_no_optional', ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] != 'optional' ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array( 'force' => 'login_update_changes_yes', 'disabled' => 'login_update_changes_no', ) ), NULL, NULL, NULL, 'login_update_name_changes_no_optional' ); $return['update_email_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_inc_optional', isset( $this->settings['update_email_changes'] ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array( 'force' => 'login_update_changes_yes', 'optional' => 'login_update_changes_optional', 'disabled' => 'login_update_changes_no', ) ), NULL, NULL, NULL, 'login_update_email_changes_inc_optional' ); $return['update_email_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_no_optional', ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] != 'optional' ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array( 'force' => 'login_update_changes_yes', 'disabled' => 'login_update_changes_no', ) ), NULL, NULL, NULL, 'login_update_email_changes_no_optional' ); \IPS\Member::loggedIn()->language()->words['login_update_name_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes'); \IPS\Member::loggedIn()->language()->words['login_update_name_changes_no_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes'); \IPS\Member::loggedIn()->language()->words['login_update_email_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_email_changes'); \IPS\Member::loggedIn()->language()->words['login_update_email_changes_no_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_email_changes'); return $return; } /** * Save Handler Settings * * @param array $values Values from form * @return array */ public function acpFormSave( &$values ) { $_values = $values; $settings = parent::acpFormSave( $values ); if ( $_values['login_handler_show_in_ucp'] == 'never' ) { $settings['update_name_changes'] = $_values['login_update_name_changes_no_optional']; $settings['update_email_changes'] = $_values['login_update_email_changes_no_optional']; } else { $settings['update_name_changes'] = $_values['login_update_name_changes_inc_optional']; $settings['update_email_changes'] = $_values['login_update_email_changes_inc_optional']; } unset( $settings['update_name_changes_inc_optional'] ); unset( $settings['update_name_changes_no_optional'] ); unset( $settings['update_email_changes_inc_optional'] ); unset( $settings['update_email_changes_no_optional'] ); return $settings; } And then implement the actual syncOptions() method like this: /** * Syncing Options * * @param \IPS\Member $member The member we're asking for (can be used to not show certain options iof the user didn't grant those scopes) * @param bool $defaultOnly If TRUE, only returns which options should be enabled by default for a new account * @return array */ public function syncOptions( \IPS\Member $member, $defaultOnly = FALSE ) { $return = array(); if ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] === 'optional' ) { $return[] = 'email'; } if ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] === 'optional' ) { $return[] = 'name'; } $return[] = 'photo'; $return[] = 'cover'; return $return; } After implementing this, there user will see the options to sync data in the area for your Login Handler in the Account Settings. Once they have configured it, Invision Community will automatically handle the syncing.
-
You will probably need some settings for the administrator to fill in when they set up a Login Method for your Handler in the AdminCP. Some settings are already provided. You do not need to do anything with them, as Invision Community will handle the values automatically: A name for the login method (the default value will be that which is provided by the getTitle() method). Whether AdminCP logins are enabled Whether new accounts are allowed If you are using a Username/Password handler: whether the user will provide a username or an email address to log in. If you override the acpForm() method, you will need to add this back in unless you have hardcoded a value for authType(). If you are using an OAuth-based handler: settings for client ID, secret, and settings related to profile syncing. There are three methods involved: acpForm() returns an array of form elements controlling what is displayed in the form. You can also return strings which will create headers. You will override this adding your own elements. acpFormSave() performs any modification of the values you want to do before saving. If not provided, the values will be saved automatically. testSettings() tests that the settings are valid. It should return TRUE or throw a LogicException if the values are not valid. You can then access the values of these settings in your login handler code through $this->settings. Here is some sample code which you could add to the sample code provided in Creating a Button Handler which would allow the administrator to change the colour of the button: /** * ACP Settings Form * * @param string $url URL to redirect user to after successful submission * @return array List of settings to save - settings will be stored to core_login_methods.login_settings DB field * @code return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... ); * @endcode */ public function acpForm() { return array( 'my_login_handler_customization', // NOTE: Create a language string for this 'button_color' => new \IPS\Helpers\Form\Color( 'my_login_handler_button_color', $this->buttonColor() ) // NOTE: Create a language string for this ); } /** * Get the button color * * @return string */ public function buttonColor() { return isset( $this->settings['button_color'] ) ? $this->settings['button_color'] : '#ff3399'; }
-
Note: For OAuth 2.0 based logins, administrators can normally use the "Other OAuth 2.0" option when creating a Login Method and provide more details in settings. However, you might want to implement a complete Login Handler to allow ease of setup or to provide additional options and features. Note: This documentation assumes familiarity with common terms and concepts used by OAuth. To make a Login Handler which uses OAuth, first change the class you have already written to extend one of these classes instead of \IPS\Login\Handler: \IPS\Login\Handler\OAuth2 for OAuth 2.0 (all grant types supported) \IPS\Login\Handler\OAuth1 for OAuth 1.0 (only 3-legged OAuth supported flow) Implementing these classes will automatically add a number of settings to allow the administrator to provide a client ID, client secret, and to control syncing for display names and email addresses/ You will then need to implement a number of methods: For all OAuth versions: authorizationEndpoint() should return the authorization endpoint URL - note that you may want to pass an additional parameter for AdminCP or reauthentication logins to provide additional security in those contexts. authenticatedUserId() should return the user ID of the authenticated user based on the access token passed. Note that for OAuth 2.0 an access token is passed, and for OAuth 1.0 both an access token and access token secret is passed. If supported, additional methods to get additional information about the authenticated user based on the access token passed: authenticatedUserName() should return the display name - you may want to add a setting to control if this is used or what kind of name is used (as is done for most of the built-in OAuth-based login handlers). authenticatedEmail() to return the email address For OAuth 2.0 only: tokenEndpoint() should return the token endpoint URL grantType() should return the grant type to use (in most cases this will be "authorization_code"). Optional: scopesToRequest() should return an array of scopes to be requested. For OAuth 1.0 only: tokenRequestEndpoint() should return the token request endpoint URL accessTokenEndpoint() should return the access token endpoint URL If the grant type you are using is button-based (which will usually be the case) you can also use the methods described in Creating a Button Handler to control the look of the button. For an example of how to implement these methods, see one of the built-in OAuth-based login handlers.
-
Note: If you are creating an OAuth-based Handler, see Creating an OAuth-Based Handler. Only use this documentation for non-OAuth-based Handlers. To make a login handler where the user clicks a button (that is not OAuth-based) you will add the \IPS\Login\Handler\ButtonHandler trait and implement the methods it requires: buttonColor(), buttonIcon(), buttonText() and buttonClass() control how the button looks. authenticateButton() handles what happens when the button is clicked. You are responsible for whatever mechanism you want to use to then authenticate the user (this will almost always involve redirecting to an external service). You will then return an \IPS\Member object (including creating the account if there isn't one already and ensuring reauthentication happens if there is already an account but the user hasn't logged in with your handler before). This is a basic skeleton of a button based Login Handler. This code will process a login using a hardcoded username and email address. Obviously a real login handler wouldn't hardcode this data but would look it up in a database or through an external service. class _MyLoginHandler extends \IPS\Login\Handler { use \IPS\Login\Handler\ButtonHandler; /** * @brief Can we have multiple instances of this handler? */ public static $allowMultiple = FALSE; /** * Get title * * @return string */ public static function getTitle() { return 'my_cusom_login_handler'; // Create a langauge string for this } /** * Authenticate * * @param \IPS\Login $login The login object * @return \IPS\Member * @throws \IPS\Login\Exception */ public function authenticateButton( \IPS\Login $login ) { /* If we haven't been redirected back, redirect the user to external site */ if ( !isset( \IPS\Request::i()->success ) ) { $urlToRedirectBackTo = $destination = $login->url->setQueryString( array( '_processLogin' => $this->id, 'csrfKey' => \IPS\Session::i()->csrfKey, 'ref' => \IPS\Request::i()->ref, ) ); // NOTE: A real example would actually redirect to an external site which would authenticate // the user and then redirect back to $urlToRedirectBackTo. But since this is just an example // we'll redirect straight to it \IPS\Output::i()->redirect( $urlToRedirectBackTo->setQueryString( 'success', 1 ) ); } /* Get the user data. NOTE: Obviously a real example would look this up in some kind of database or external service or it would have been returned as the user was redirected back */ $userId = 1; // NOTE: This would be set to some kind of identifier for the user within that service. It doesn't have to be numeric, but does have to be unique. $name = 'example'; // NOTE: We will use this later to create an account if it doesn't exist. If your login handler doesn't store display names, set this to NULL (and the user will be asked to provide one) $email = 'example@example.com'; // NOTE: We will use this later to create an account if it doesn't exist. If your login handler doesn't store display names, set this to NULL (and the user will be asked to provide one) /* Find their local account if they have already logged in using this method in the past */ try { $link = \IPS\Db::i()->select( '*', 'core_login_links', array( 'token_login_method=? AND token_identifier=?', $this->id, $userId ) )->first(); $member = \IPS\Member::load( $link['token_member'] ); /* If the user never finished the linking process, or the account has been deleted, discard this access token */ if ( !$link['token_linked'] or !$member->member_id ) { \IPS\Db::i()->delete( 'core_login_links', array( 'token_login_method=? AND token_member=?', $this->id, $link['token_member'] ) ); throw new \UnderflowException; } /* ... and return the member object */ return $member; } catch ( \UnderflowException $e ) { } /* Otherwise, we need to either create one or link it to an existing one */ try { /* If the user is setting this up in the User CP, they are already logged in. Ask them to reauthenticate to link those accounts */ if ( $login->type === \IPS\Login::LOGIN_UCP ) { $exception = new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT ); $exception->handler = $this; $exception->member = $login->reauthenticateAs; throw $exception; } /* Try to create one. NOTE: Invision Community will automatically throw an exception which we catch below if $email matches an existing account, if registration is disabled, or if Spam Defense blocks the account creation */ $member = $this->createAccount( $name, $email ); /* If we're still here, a new account was created. Store something in core_login_links so that the next time this user logs in, we know they've used this method before */ \IPS\Db::i()->insert( 'core_login_links', array( 'token_login_method' => $this->id, 'token_member' => $member->member_id, 'token_identifier' => $userId, 'token_linked' => 1, ) ); /* Log something in their history so we know that this login handler created their account */ $member->logHistory( 'core', 'social_account', array( 'service' => static::getTitle(), 'handler' => $this->id, 'account_id' => $userId, 'account_name' => $name, 'linked' => TRUE, 'registered' => TRUE ) ); /* Set up syncing options. NOTE: See later steps of the documentation for more details - it is fine to just copy and paste this code */ if ( $syncOptions = $this->syncOptions( $member, TRUE ) ) { $profileSync = array(); foreach ( $syncOptions as $option ) { $profileSync[ $option ] = array( 'handler' => $this->id, 'ref' => NULL, 'error' => NULL ); } $member->profilesync = $profileSync; $member->save(); } return $member; } catch ( \IPS\Login\Exception $exception ) { /* If the account creation was rejected because there is already an account with a matching email address make a note of it in core_login_links so that after the user reauthenticates they can be set as being allowed to use this login handler in future */ if ( $exception->getCode() === \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT ) { \IPS\Db::i()->insert( 'core_login_links', array( 'token_login_method' => $this->id, 'token_member' => $exception->member->member_id, 'token_identifier' => $userId, 'token_linked' => 0, ) ); } throw $exception; } } /** * Get the button color * * @return string */ public function buttonColor() { return '#ff3399'; } /** * Get the button icon * * @return string */ public function buttonIcon() { return 'sign-in'; // A fontawesome icon } /** * Get button text * * @return string */ public function buttonText() { return 'sign_in_with_my_cusom_login_handler'; // Create a language string for this } /** * Get button CSS class * * @return string */ public function buttonClass() { return ''; } }
-
To make a login handler where the user enters a username or email address and password you will add the \IPS\Login\Handler\UsernamePasswordHandler trait to your Login Handler class and implement the two methods it requires: authenticateUsernamePassword() is called when a user enters a username or email address and password into the login form. You need to verify if it is valid in your login handler and return an \IPS\Member object if it is (including creating the account if there isn't one already and ensuring reauthentication happens if there is already an account but the user hasn't logged in with your handler before) or throw an \IPS\Login\Exception exception if not. authenticatePasswordForMember() is called when a user is doing something sensitive and is being asked to reauthenticate by entering their password from your login handler again to confirm. This is a basic skeleton of a username/password based Login Handler. This code will process a login for the a hardcoded username/email address and password. Obviously a real login handler wouldn't hardcode this data but would look it up in a database or through an external service. class _MyLoginHandler extends \IPS\Login\Handler { use \IPS\Login\Handler\UsernamePasswordHandler; /** * @brief Can we have multiple instances of this handler? */ public static $allowMultiple = FALSE; /** * Get title * * @return string */ public static function getTitle() { return 'my_cusom_login_handler'; // Create a langauge string for this } /** * Authenticate * * @param \IPS\Login $login The login object * @param string $usernameOrEmail The username or email address provided by the user * @param string $password The plaintext password provided by the user * @return \IPS\Member * @throws \IPS\Login\Exception */ public function authenticateUsernamePassword( \IPS\Login $login, $usernameOrEmail, $password ) { /* Is this a user we can process? NOTE: Obviously a real login handler would look up $usernameOrEmail in some kind of database or external service */ $authType = $this->authType(); // NOTE: The UsernamePasswordHandler trait has automatically provided a setting in this login method which allows the administrator to choose if the user will enter a username, email address, or either if ( ( $authType & \IPS\Login::AUTH_TYPE_USERNAME and $usernameOrEmail === 'example' ) or ( $authType & \IPS\Login::AUTH_TYPE_EMAIL and $usernameOrEmail === 'example@example.com' ) ) { $userId = 1; // NOTE: This would be set to some kind of identifier for the user within that service. It doesn't have to be numeric, but does have to be unique. $name = 'example'; // NOTE: We will use this later to create an account if it doesn't exist. If your login handler doesn't store display names, set this to NULL (and the user will be asked to provide one) $email = 'example@example.com'; // NOTE: We will use this later to create an account if it doesn't exist. If your login handler doesn't store display names, set this to NULL (and the user will be asked to provide one) } else { switch ( $this->authType() ) { case \IPS\Login::AUTH_TYPE_USERNAME + \IPS\Login::AUTH_TYPE_EMAIL: $type = 'username_or_email'; break; case \IPS\Login::AUTH_TYPE_USERNAME: $type = 'username'; break; case \IPS\Login::AUTH_TYPE_EMAIL: $type = 'email_address'; break; } throw new \IPS\Login\Exception( \IPS\Member::loggedIn()->language()->addToStack( 'login_err_no_account', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $type ) ) ) ), \IPS\Login\Exception::NO_ACCOUNT ); } /* Find their local account if they have already logged in using this method in the past */ $member = NULL; try { $link = \IPS\Db::i()->select( '*', 'core_login_links', array( 'token_login_method=? AND token_identifier=?', $this->id, $userId ) )->first(); $member = \IPS\Member::load( $link['token_member'] ); /* If the user never finished the linking process, or the account has been deleted, discard this access token */ if ( !$link['token_linked'] or !$member->member_id ) { \IPS\Db::i()->delete( 'core_login_links', array( 'token_login_method=? AND token_member=?', $this->id, $link['token_member'] ) ); $member = NULL; } } catch ( \UnderflowException $e ) { } /* Is the password valid? NOTE: Obviously a real login handler would actually verify the password is correct for the member. This step is done AFTER looking up their local account so that their account can be locked if they provide multiple wrong passwords */ if ( $password !== 'example' ) { throw new \IPS\Login\Exception( 'login_err_bad_password', \IPS\Login\Exception::BAD_PASSWORD, NULL, $member ); } /* If we have a local account, go ahead and return it */ if ( $member ) { return $member; } /* Otherwise, we need to either create one or link it to an existing one */ try { /* If the user is setting this up in the User CP, they are already logged in. Ask them to reauthenticate to link those accounts */ if ( $login->type === \IPS\Login::LOGIN_UCP ) { $exception = new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT ); $exception->handler = $this; $exception->member = $login->reauthenticateAs; throw $exception; } /* Try to create one. NOTE: Invision Community will automatically throw an exception which we catch below if $email matches an existing account, if registration is disabled, or if Spam Defense blocks the account creation */ $member = $this->createAccount( $name, $email ); /* If we're still here, a new account was created. Store something in core_login_links so that the next time this user logs in, we know they've used this method before */ \IPS\Db::i()->insert( 'core_login_links', array( 'token_login_method' => $this->id, 'token_member' => $member->member_id, 'token_identifier' => $userId, 'token_linked' => 1, ) ); /* Log something in their history so we know that this login handler created their account */ $member->logHistory( 'core', 'social_account', array( 'service' => static::getTitle(), 'handler' => $this->id, 'account_id' => $userId, 'account_name' => $name, 'linked' => TRUE, 'registered' => TRUE ) ); /* Set up syncing options. NOTE: See later steps of the documentation for more details - it is fine to just copy and paste this code */ if ( $syncOptions = $this->syncOptions( $member, TRUE ) ) { $profileSync = array(); foreach ( $syncOptions as $option ) { $profileSync[ $option ] = array( 'handler' => $this->id, 'ref' => NULL, 'error' => NULL ); } $member->profilesync = $profileSync; $member->save(); } return $member; } catch ( \IPS\Login\Exception $exception ) { /* If the account creation was rejected because there is already an account with a matching email address make a note of it in core_login_links so that after the user reauthenticates they can be set as being allowed to use this login handler in future */ if ( $exception->getCode() === \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT ) { \IPS\Db::i()->insert( 'core_login_links', array( 'token_login_method' => $this->id, 'token_member' => $exception->member->member_id, 'token_identifier' => $userId, 'token_linked' => 0, ) ); } throw $exception; } } /** * Authenticate * * @param \IPS\Member $member The member * @param string $password The plaintext password provided by the user * @return bool */ public function authenticatePasswordForMember( \IPS\Member $member, $password ) { // NOTE: Obviously a real login handler would actually verify the password is correct for the member. You may want to write a separate method // which can be called by both this method and authenticateUsernamePassword() so that the code isn't duplicated return $member->email === 'example@example.com' and $password === 'example'; } } Note: The \IPS\Login\Handler\UsernamePasswordHandler trait will automatically add a setting to allow the administrator to choose if the user will provide a username or email address to sign in, and this value is returned to you by the authType() method. If this does not apply to your login handler, you will need to override it. For example, if your login handler can only accept email addresses, you will need to add this code within your class: /** * ACP Settings Form * * @return array List of settings to save - settings will be stored to core_login_methods.login_settings DB field * @code return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... ); * @endcode */ public function acpForm() { return array(); // Remove the setting set by the UsernamePasswordHandler trait } /** * Get auth type * * @return int */ public function authType() { return \IPS\Login::AUTH_TYPE_EMAIL; }
-
Note: This documentation applies to Invision Community 4.3 and higher only. For older versions, see 4.2 and below: Login Handlers. Basic functionality will be backwards compatible. Introduction Invision Community allows users to log in using a number of different Login Handlers. For example, in addition to the "Standard" login handler where the user enters their email address or display name and password that they used to register, users can also log in with their Facebook account, or using credentials provided by an external MySQL database. A Login Handler which has been set up is called a Login Method. Some Login Handlers can be used more than once (creating multiple Methods) and some cannot. For example, you can have multiple external MySQL databases but there is only one Facebook. Types and Class Structure All Login Handlers extend the abstract \IPS\Login\Handler class. Login Handlers can work in two ways: Username/Password Handlers allow the user to enter either a display name or an email address and a password (for example: the Standard handler, external MySQL database, LDAP directory). These will use the \IPS\Login\Handler\UsernamePasswordHandler trait. Button Handlers work by the user clicking a button which redirects them to an external site to authenticate (for example: Facebook, Twitter, etc.). These will use the \IPS\Login\Handler\ButtonHandler trait. Usually a Login Handler will only use one of these traits, however it can use both and change its behaviour based on how the Method is configured. There are also base classes for OAuth-based handlers (one for OAuth 1.0 and one for OAuth 2.0) which extend \IPS\Login\Handler to provide some shared code between Login Handlers which use OAuth. This is the class structure of all the Login Handlers provided in Invision Community by default: abstract \IPS\Login\Handler abstract \IPS\Login\Handler\OAuth2 uses \IPS\Login\Handler\UsernamePasswordHandler and \IPS\Login\Handler\ButtonHandler \IPS\Login\Handler\OAuth2\Facebook \IPS\Login\Handler\OAuth2\Google \IPS\Login\Handler\OAuth2\LinkedIn \IPS\Login\Handler\OAuth2\Microsoft \IPS\Login\Handler\OAuth2\Invision \IPS\Login\Handler\OAuth2\Wordpress \IPS\Login\Handler\OAuth2\Custom abstract \IPS\Login\Handler\OAuth1 \IPS\Login\Handler\OAuth1\Twitter \IPS\Login\Handler\ExternalDatabase \IPS\Login\Handler\LDAP Understanding the Flow When a user uses a Login Method they may or may not already have an account in the community's database. If the authentication is successful, one of three things will happen: If the user has logged in with that Login Method before (for example, they are logging in with Facebook and have done that on that community before), the Login Handler will return the \IPS\Member object for the member, and they will be logged straight in. If the user has not logged in with that Login Method before, the Login Handler will attempt to create an account, optionally providing (if it knows them) a display name and an email address. Invision Community will then either: If there is already an account in the database with the same email address as what the Login Handler provided, the user will be prompted to link the accounts by authenticating with another Login Method they have used before (usually this means entering their password). If there is not already an account with the same email address, or the Login Handler did not provide an email address, an account will be created (unless the administrator has configured the Login Method to not allow new accounts to be created) and the user will either be logged straight in, be prompted for more information to create their account, or be required to validate, depending on what information the Login Handler provides and what settings the administrator has chosen. Getting Started To get started with a basic skeleton Login Handler: With Developer Mode enabled, create an application you will use for your Login Handler from the Applications page in the AdminCP. Create a class for your login handler using the skeleton below. You will need to set an appropriate value for $allowMultiple (see above more information) and return the key for the language string you just created in the getTitle() method. Create a code hook on the \IPS\Login\Handler class to add the name of the class you just created to the value returned by \IPS\Login\Handler::handlerClasses(). See below for sample code. Login Handler Skeleton <?php namespace IPS\mycustomloginhandler; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } class _MyCustomLoginHandler extends \IPS\Login\Handler { /** * @brief Can we have multiple instances of this handler? */ public static $allowMultiple = FALSE; /** * Get title * * @return string */ public static function getTitle() { return 'my_cusom_login_handler'; // Create a langauge string for this } } Sample Code Hook //<?php /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { exit; } abstract class mycustomloginhandler_hook_loginHandlerHook extends _HOOK_CLASS_ { public static function handlerClasses() { $return = parent::handlerClasses(); $return[] = 'IPS\mycustomloginhandler\MyLoginHandler'; return $return; } } Next Steps Follow the instructions specific to the type of Login Handler you are creating, creating any settings you need as you do so: Username/Password Handlers Button Handlers OAuth-Based Handlers Follow instructions for adding profile syncing Follow instructions for adding any advanced features you need
-
This is a maintenance to release to address security issues. As we prepare for our next large release, version 4.3, we do large security audits. We decided to apply those security enhancements to the 4.2 series so you can get them now while we begin public betas of 4.3. We would like to thank @newbie LAC for his assistance.
-
Introduction You can link Invision Community with a Wordpress site to allow users to sign into one community using their credentials from another. First you need to decide which direction the login should happen: Allow users to log into your Invision Community with their account on a Wordpress site (Wordpress as the Server). Allow users to log into your Wordpress site with their account on an Invision Community (Invision Community as the Server). Only follow the instructions below for which direction you want. SSL is required on both Invision and word press. Option A: Wordpress as the Server 1. Setup the Wordpress Plugin First you will need to install the OAuth Server plugin for Wordpress to enable OAuth functionality on your Wordpress site. To do this, from your Wordpress Dashboard, go to Plugins > Add New, search for OAuth server. Find the miniOrange OAuth 2.0 Server/Provider by miniOrange (there are several plugins with similar names available) and click Install, and once it has installed, click Activate. Installing Wordpress Plugin After it has installed, go to the new miniOrange OAuth Server section and follow the instructions to complete the registration process. 2. Create the Client On your community, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose Wordpress. Meanwhile, from your Wordpress Dashboard, go to miniOrange OAuth Server -> Add Client. Enter a name (such as the name of your community) and for the Authorized Redirect URI field enter the value shown in your AdminCP, which will be your community's URL ending with "/oauth/callback/" on the end. You should now see a screen with a Client ID and Client Secret. Wordpress Client Details 3: Set up Invision Community Back in your AdminCP, fill in the form, using the Client ID and Client Secret that you just obtained. You will also need to configure the text, color and logo to use for the button that users will click on to log in. Enterring details in Invision Community You should now be able to log into Invision Community through Wordpress! Option B: Invision Community as the Server 1. Configure Invision Community On your Invision Community, go to AdminCP -> System -> REST & OAuth and click Create New and fill out the form selecting Wordpress for Client Type. You will then see a screen with details you will need to enter into Wordpress. Client Details for Wordpress 2. Configure Wordpress Initial Setup First, from your Wordpress Dashboard, go to Settings > Permalinks. You must have the Post name option selected. If you haven't, change this and save the form. Installing the Plugin Next you will need to install the oAuth Login plugin for Wordpress to enable OAuth functionality on your Wordpress site. To do this, from your Wordpress Dashboard, go to Plugins > Add New, search for OAuth login. Find the OAuth Single Sign On - SSO (OAuth client) by miniOrange (there are several plugins with similar names available) and click Install, and once it has installed, click Activate. Installing Wordpress Plugin After it has installed, go to the new miniOrange OAuth section and follow the instructions to complete the registration process. Creating the Client You can now enter the client details in Wordpress. Enter all of the details exactly as they are shown in your Invision Community AdminCP. Please note: we have noticed that if you choose the "Invision Community" option, some versions of the plugin pre-enter the value for Get User Info Endpoint as https://<your-domain>/oauth/core/me but the correct value is either https://<your-domain/api/core/me or https://<your-domain/api/index.php?/core/me - make sure you enter the correct value shown in your AdminCP. Enterring details in Wordpress You then need to add the sign in button in your desired location. For details on how to do this, go to the Sign In Settings tab for information. You can also configure how the button appears under the Customizations tab. Once this is done, you will see the sign in button on your Wordpress site. Sign In Button on an Example Wordpress Site
-
This integration requires access to the legacy Twitter 1.0 API. New developer accounts do not have access to this. We are working on migrating to Twitter 2.0 API, this guide will be updated when this has been completed. You can allow your members to sign in to your community using their Twitter account. To start the process, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose Twitter. You will now be prompted to fill in some details which you'll need to acquire by creating an "app" with Twitter. Getting API Access Before you are able to create a twitter application, you first need to get access to the twitter API. To do this, visit https://apps.twitter.com and sign in with your twitter account. If you click on create app, it will ask you to first apply for access to the API. Click apply first of all. Once you have done this, you will be presented with the following screen, which you need to select "Doing something else" from the options. Choose Reason Once you have selected the reason, you will be asked to confirm your details. Unless you have any pressing reason to do so, you should click next at the bottom of the page. API developer Details You will now be asked a series of questions related to the use of the API on your site. Here we will be filling in the "In your words" section at the top, and the "Do you plan to display tweets............outside of twitter?" section at the bottom. All other items should have "No" selected. For the first item of "In your words" you need to enter something like the following screenshot. In your words For the last section, enter something like the below Data outside twitter Click next to complete the application. You will be asked to confirm your email address. Ensure you do this before continuing to the next section of our guide below. Creating a Twitter App 1. Go to the Twitter Application Management site and sign in with your Twitter account. 2. Click Create App and fill out the form. For the Website field, enter the URL to your community. For the Callback URLs field enter the value shown in your AdminCP, which will be your community's URL ending with "/oauth/callback/" on the end. 3. Go to the Settings tab and make sure the Allow this application to be used to Sign in with Twitter checkbox is checked. Then also provide a value for the Privacy Policy URL and the Terms of Service URL (you can create pages for these in your AdminCP under System -> Terms & Privacy Policy if you haven't already). Make sure you click Update Settings to save. Twitter Settings tab 4. Go to the Permissions tab and click Edit. Ensure that Access is set to Read and Write, and then check the Request email addresses from users checkbox (it will not be checked by default). Make sure you click Update Settings to save. Twitter Permissions tab 5. Go to the Keys and tokens tab to obtain the values you need to enter into the AdminCP. Twitter Keys and Access Tokens tab Back in your AdminCP, fill in the form, using the Consumer Key and Consumer Secret that is shown on the Keys and Access Tokens tab from Twitter. Entering details in Invision Community
-
You can allow your members to sign in to your community using their Microsoft account. To start the process, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose Microsoft. You will now be prompted to fill in some details which you'll need to acquire by creating an "app" with Microsoft. Creating a Microsoft App 1. Go to the Microsoft Azure App registrations page and sign in with your Microsoft account. 2. Click New Registration and fill in a name (just use the name of your community). 3. Unless you have a specific need to change it, under "Supported account types" leave "Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com)" selected. 4. Under the field labelled Redirect URI, leave the dropdown selected as "Web" and then enter the value shown in your AdminCP into the text field. You must then click Register at the bottom to save this. App Details Page 5. Copy the Application (client) ID shown on this page, along with password, into the AdminCP under Application Id. ACP screen 6. In the Azure App registrations page for the application you just created, click Certificates & secrets in the left hand menu. Click the New client secret button. Set the secret to Never expire, provide an optional description, and click the Add button. Creating client secret 7. Copy the value displayed on the Certificates & secrets page after adding a new client secret and paste it in to the AdminCP as the Password. 8. Finish creating the new Login Method and verify you are able to successfully log in to your community using a valid Microsoft account.
-
You can allow your members to sign in to your community using their LinkedIn account. To start the process, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose LinkedIn. You will now be prompted to fill in some details which you'll need to acquire by creating an "application" with LinkedIn. Creating an application with LinkedIn 1. Go to the LinkedIn Developers page and sign in with your LinkedIn account. 2. Click Create App and fill in the form. 3. You will now see your application details. Click on the Auth tab, and then under the OAuth 2.0 settings section, you will see a field labelled Redirect URLs. Click the pencil icon to edit this setting, and add the value shown in your AdminCP. You must click Update at the bottom to save this. LinkedIn Application Page 4. On the 'Products' tab, select "Sign In with LinkedIn", accept the terms, and click to add this. (You will need to await approval for this) Products Adding 5.Back in your AdminCP, fill in the form, using the Client ID and Client Secret that are shown on the LinkedIn application Auth screen. Entering details in Invision Community
-
You can allow your members to sign in to your community using their Facebook account. In order to use facebook, your site must be on a secure https domain. You can see more information on how to switch to https after obtaining an SSL certicate from your hosting company in the following guide Basic Facebook Login To start the process, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose Facebook. You will now be prompted to fill in some details which you'll need to acquire by creating an "app" with Facebook. Creating a Facebook App 1. Go to the Meta for Developers site and sign in with your Facebook account. 2. If you have not already registered with Facebook for Developers, click Register Now and follow the instructions to register 3. Click on My Apps in the top right, then select 'Create App Click to create a new app 4.Select "None" when asked for an app type App Type Selection 5. Add a name for the login and an email address, then click create app Facebook App Dashboard 6. Select "Facebook Login" from the product list 6. Select "www" and from the quickstart list 7. Add your site URL, then click continue 8. The next 3 screens can be ignored. Click on next on each until you get to the last section, then go to the next step. 9. Click on "basic"You will then be taken to the basic settings page for the new application. Here you need to add your privacy policy, and your terms of service, and logo, then save. Basic Settings 7. Go to the Products > Facebook Login > Settings tab from the left sidebar. In the Valid OAuth redirect URIs field enter the value shown in your AdminCP, which will be your community's URL ending with "/oauth/callback/" on the end. You must click Save Changes at the bottom to save this. Callback URL Set Up Invision Community Go to Settings > Basic from the left sidebar. You will see your App ID and a button to reveal the App Secret. Back in your ACP, fill in the form, using these details. App ID and Secret Now go to the front-end of your community, log out, and log in with the Sign in with Facebook button. At this point, only your own Facebook account, which you used to create the client, will work. If it works, you can continue to the next step. Entering details in Invision Community Once you have done the above, you will be able to use facebook to login to your community. Go Live IMPORTANT: - Do not go live with your product, until you have completed any application permission reviews required by facebook for Statuses, and/or social media promotion. In the top-right you will see an On/Off switch next to Status: In Development. Click the on/off switch and confirm. The switch should now indicate On and you should see Status: Live. Live Facebook App Note if you wish to enable status imports, you will need to add more permissions and get your application permissions reviewed by facebook. You should then continue below. If you only want sign in ability, you are finished at this point Optional: Enabling Status Imports Before you begin, please note, we can give advice on how to fill this in, however some details may vary based on your own uses. You will also need business verification in order to set this up. This is per facebooks guidelines. When setting up Facebook Login in your AdminCP you will have seen a Allow Status Imports? setting which mentions requiring additional setup. Using this feature means gaining access to restricted Facebook APIs, which, before you can do, you need to get approval from Facebook. 1. To get started, enable the Allow Status Imports? setting from AdminCP -> System -> Login & Registration -> Facebook. 2. On the Facebook for Developers site, go to App Review -> Permissions and Features from the left-side menu. Use the search box at the top to search for user_posts 3. select the "Request" option then select continue 4. You will now see the review, for each of the items you have chosen, there is an Add Details link. Request a review Click Add Details and fill in the form. An example of what to provide can be seen below. In addition to these information, you will need to provide a screencast of you demonstrating that process of signing in with Facebook and doing the thing you are asking Facebook for permission for (importing a status or automatically sharing to Facebook). Make sure your video shows you doing exactly the steps in the instructions you provided otherwise your review will likely be rejected. You do this by using your own account and switching your facebook application to developer mode This video needs to show your community, so we cannot provide a video for you to send to Facebook - you must record and submit it yourself. For Tell us how you're using this permission or feature enter something like the following: For Demontrate how your selected platforms will use this permission or feature? choose Web. Under this option, you will need to stated how this is used by the user. Enter the following information to show how a user logs in (please modify if your options are in different places due to theming or 3rd party items) You will then additionally need to do a screencast to show on video how the system is used. This can be uploaded to the same form. Click on save once complete 6. Click Submit For Review to submit the review and confirm the submission. You will be advised how long it will take you for Facebook to approve the submission, and should receive an email once it is complete
-
You can allow your members to sign in to your community using their Google account. Applies to self-hosted customers only Important - Google requires that sites using their login API, are using a secure connection. If your site is not using SSL (HTTPS), please contact your hosting company to obtain a valid SSL certicate, then follow this guide to switch to https. https://invisioncommunity.com/4guides/advanced-options/configuration-options/using-ssl-https-r273/ To start the process, go to AdminCP -> System -> Login & Registration, click Create New to setup a new login method and choose Google. You will now be prompted to fill in some details which you'll need to acquire by creating a "project" with Google. Creating a project 1. Go to the Google APIs Console and sign in with your Google account. You may have created a project if you have enabled any other Google APIs. If you haven't, click Select a Project in the top-left corner and then create a new project. No Project Selected Project Selected 2. Go to Library and search for Google Identity. Click on "Cloud Identity" and then click on 'enable' Adding Credentials 3. Go to Credentials -> OAuth consent screen and fill out the form. 4. Go to Credentials -> Credentials. Click the Create credentials button and choose OAuth client ID from the dropdown. Create Credentials Button Choose Web application as the type, and for the Authorized redirect URIs field, enter the value shown in your AdminCP. Credentials Form Adding to the ACP You will see a screen displaying a client ID and client secret. Issued Credentials Back in your AdminCP, fill in the form, using the Client ID and Client Secret that you just obtained. Entering details in Invision Community Updating from google+ Updating from the google+ API due to the replacing of these APIs by google can be done in the following manner 1. Go to the Google APIs Console and sign in with your Google account and select your google project. 2. Select to remove the google+ API 3. Go to Library and search for Google Identity. Click on "Cloud Identity" and then click on 'enable' No further steps are required to switch to the new API as you already have credentials created from the previous setup.