Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 141 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,170 @@
# PresideCMS Extension: Social Media Login
# PresideCMS Social Login

This is an extension for [PresideCMS](http://github.com/pixl8/Preside-CMS/) that enables signing up / logging in using third party/social media login such as Facebook, Twitter and Google
This PresideCMS extension supports secure website-user login with:

## How it works
- Facebook Login
- Google OpenID Connect
- X OAuth 2.0
- Sign in with LinkedIn using OpenID Connect

The extension extends the current Login functionality for Website users in preside to enable them to sign up or login using social media credentials.
The implementation uses authorization-code flows, one-time session-bound `state`, PKCE where the provider supports it, short callback lifetimes, server-side token exchange, and explicit account linking.

You will need to create an application/project on the social media platform from the steps below to obtain API keys for respective platform. The key can be then keyed in in the Social Media Login settings under System > Settings in preside.
## Requirements

### Facebook
- A PresideCMS application with website users enabled
- HTTPS for every non-local environment
- A provider application for each enabled login option
- A stable public hostname; callback URLs must match exactly

Create a Facebook application at https://developers.facebook.com/apps/. The crendentials for Facebook can be obtained from the Facebook application settings.
Twitter4j is no longer used or required.

### Twitter
## Install

Create a new Twitter application at https://apps.twitter.com. The credentials for Twitter can be obtained from your Twitter application's Key and Access Tokens
From the root of the Preside application:

### Google
```bash
box install seakchiew/preside-ext-social-login
```

Create a new project at https://console.developers.google.com/ and create a new OAuth 2.0 client ID and an API Key under credentials.
Alternatively, install this repository under:

## Installation
```text
application/extensions/preside-ext-social-login
```

Install the extension to your application via either of the methods detailed below (Git submodule / CommandBox) and then enable the extension by opening up the Preside developer console and entering:
Enable and reload it in the Preside developer console:

extension enable preside-ext-social-login
reload all
```text
extension enable preside-ext-social-login
reload all
```

### Git Submodule method
Run the Preside database synchronisation after upgrading. Version 1 adds `label` and `email_verified` to `social_account` and creates a unique `(type, social_id)` identity constraint.

From the root of your application, type the following command:
## Callback URLs

git submodule add https://github.com/seakchiew/preside-ext-social-login.git application/extensions/preside-ext-social-login
Replace `https://example.com` with the canonical site URL. Register each URL exactly, including its query string:

### CommandBox (box.json) method
```text
https://example.com/login/auth/?type=facebook
https://example.com/login/auth/?type=google
https://example.com/login/auth/?type=twitter
https://example.com/login/auth/?type=linkedin
```

From the root of your application, type the following command:
Do not register wildcard callback URLs. If a provider normalises away the slash before `?`, verify the URL emitted by the running site and register that exact value.

box install seakchiew/preside-ext-social-login
## Preside configuration

# Reference
Open **System → Settings → Social login**.

This script is based on multiple login script by cfjquery - https://github.com/cfjquery/multiLogin
1. Enter the client ID and client secret for a provider.
2. Enable that provider.
3. Save the settings.
4. Reload the login page and confirm the provider button appears.

A provider button remains hidden when its toggle is enabled but either credential is blank. Restrict access to the settings category because provider secrets are stored in Preside system configuration.

## Dependency
## Facebook

The Twitter API authentication uses Twitter4j java library
Please download the library from http://twitter4j.org/en/index.html and place twitter4j-core.*.jar into /WEB-INF/lib/ folder in your application
1. Open [Meta for Developers](https://developers.facebook.com/apps/) and create an app.
2. Add the **Facebook Login** product and select the web platform.
3. Under Facebook Login settings, add the Facebook callback URL to **Valid OAuth Redirect URIs**.
4. Request the `email` and `public_profile` permissions. Complete App Review if Meta requires it for the app’s audience.
5. Keep **Client OAuth Login**, **Web OAuth Login**, and strict redirect URI matching enabled.
6. Copy the app ID and app secret into the Facebook tab in Preside.
7. Enable Facebook login.

The extension targets Graph API `v25.0`, sends PKCE and `state`, uses the bearer-token header for `/me`, and signs the profile request with `appsecret_proof`.

## Google

1. Open [Google Cloud Console](https://console.cloud.google.com/apis/credentials).
2. Configure the OAuth consent screen.
3. Create an **OAuth client ID** with application type **Web application**.
4. Add the Google callback URL under **Authorized redirect URIs**.
5. Add production domains and test users as required by the consent-screen publishing status.
6. Copy the client ID and client secret into the Google tab in Preside.
7. Enable Google login.

The requested scopes are `openid email profile`. The extension uses Google’s current authorization, token, and OpenID Connect UserInfo endpoints.

## X

1. Open the [X Developer Portal](https://developer.x.com/) and create or select a project and app.
2. Enable **OAuth 2.0** user authentication.
3. Select a confidential **Web App** client.
4. Add the X callback URL.
5. Add the site URL as the website URL.
6. Grant the `tweet.read` and `users.read` scopes.
7. Copy the OAuth 2.0 client ID and client secret into the X tab in Preside.
8. Enable X login.

Legacy OAuth 1.0a API keys are not compatible. Upgrades must enter new OAuth 2.0 client credentials. X does not return an email for this flow; the extension uses the stable X user ID as the website-user login ID and a unique, non-deliverable `@social-login.invalid` address until the application collects and verifies a local address.

## LinkedIn

1. Open [LinkedIn Developers](https://www.linkedin.com/developers/apps) and create an app.
2. Associate and verify the app with a LinkedIn Page.
3. On **Products**, request **Sign in with LinkedIn using OpenID Connect**.
4. Add the LinkedIn callback URL under **Authorized redirect URLs for your app**.
5. Confirm the app has `openid`, `profile`, and `email`.
6. Copy the client ID and client secret into the LinkedIn tab in Preside.
7. Enable LinkedIn login.

LinkedIn’s web OIDC endpoint does not consistently accept PKCE parameters. This provider therefore uses a confidential-client authorization-code flow with an exact callback URI, one-time `state`, a client secret, and a ten-minute local flow lifetime.

## Explicitly link an existing account

Social login never attaches an identity to an existing website user merely because email addresses match. The user must first sign in normally and submit a CSRF-protected link request.

Add a form like this to the authenticated account page for each enabled provider:

```cfm
<cfoutput>
<form action="#event.buildLink( linkTo="login.linkSocialAccountAction" )#" method="post">
<input type="hidden" name="csrfToken" value="#event.getCsrfToken()#">
<input type="hidden" name="type" value="google">
<input type="hidden" name="postLoginUrl" value="/account/social-logins/">
<button type="submit">Link Google account</button>
</form>
</cfoutput>
```

Valid `type` values are `facebook`, `google`, `twitter`, and `linkedin`. Linking is rejected for anonymous, remember-me-only, and administrator-impersonated sessions. A social identity already linked to another website user cannot be moved.

## Verification checklist

Run this for each provider in a test environment:

1. Disable the provider and confirm its button disappears and direct initiation is rejected.
2. Enable it with valid credentials and complete a first-time login.
3. Confirm one `social_account` record and one linked `website_user` record are created.
4. Log out and repeat; confirm no duplicate records are created.
5. Start login in one browser and alter `state` in the callback; confirm login fails.
6. Reuse a successful callback; confirm login fails because flow state is single-use.
7. Start a flow, wait more than ten minutes, and confirm callback rejection.
8. Use a social account whose email already belongs to a website user; confirm it is not logged in or linked.
9. Sign in normally and use the CSRF-protected linking form; confirm linking succeeds.
10. Supply an external `postLoginUrl`; confirm the redirect remains on the application origin.
11. Deny consent and confirm the user returns to the login page without provider details or tokens in logs.

## Automated tests

Security regression specs are under `tests/specs`. Run them from a Preside/TestBox test harness that maps this extension at the application root:

```bash
box testbox run
```

Provider end-to-end tests require real sandbox applications and secrets, so keep them in a protected deployment environment rather than the repository.

## Upgrade notes from 0.1

- X OAuth 1.0a and Twitter4j were removed.
- Facebook and Google legacy credential names are read as fallbacks, but save credentials into the new fields.
- Base URL, redirect URL, API key, and configurable Facebook field settings were removed because they were unused and unsafe.
- Existing email-matched accounts are not changed automatically. Users must explicitly link future social identities.
- Providers that do not return a verified email receive a unique `@social-login.invalid` placeholder because Preside requires `website_user.email_address`; applications should replace it through their normal verified-email workflow.

See [SECURITY_AUDIT.md](SECURITY_AUDIT.md) for findings, remediation details, residual risks, and standards references.
Loading