# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
This site has an agentic ask interface you may use to query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://cbauth.ortusbooks.com/index.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

---

# Introduction

Authentication is tedious. Many projects need some sort of authentication system. And in many of these projects you will basically start from scratch. That's why `cbauth` was created.

cbauth is a library that handles creating user sessions for your app including authenticating users, logging users in and out, and retrieving the currently authenticated user. It is customizable to plug in to your existing authentication method and session storage.

{% hint style="info" %}
cbauth is designed to be customized for existing applications.  As such, it requires some work to configure correctly.  If you are starting a new project and would like this configuration done for you check out the pre-configured application templates on ForgeBox like [`quick-with-auth`](https://forgebox.io/view/cbtemplate-quick-with-auth) and [`quick-tailwind-inertia`](https://forgebox.io/view/cbtemplate-quick-tailwind-inertia).
{% endhint %}

These are some of the methods you can use in your project:

```javascript
auth.authenticate( username, password );
auth.isLoggedIn();
auth.getUser();
auth.logout();
```

{% hint style="warning" %}
While `cbauth` manages user sessions, it doesn't protect handlers or actions from being accessed by logged out our unauthorized users. This part of the job is left to libraries such as [cbsecurity](https://coldbox-security.ortusbooks.com/) or [cbguard](https://www.forgebox.io/view/cbguard).
{% endhint %}


# What's New

## v5.0.1

### 24 Apr 2020 — 03:47:00 UTC

#### other

* **\*:** fix: Allow any dsl to be the user service ([7cfb533](https://github.com/coldbox-modules/cbauth/commit/7cfb533f9b06f924961bd5f900e843801b2506e8))

## v5.0.0

### 02 Apr 2020 — 22:10:08 UTC

#### BREAKING

* **\*:** feat: Added interception points and return user from authorize ([778cd73](https://github.com/coldbox-modules/cbauth/commit/778cd739e80a73d3efe772e0475b2ed9db9db088))

## v4.1.2

### 18 Feb 2020 — 17:27:02 UTC

#### other

* **\*:** Adjust gitignore file for better directory matching ([a2d0ba3](https://github.com/coldbox-modules/cbauth/commit/a2d0ba3e52a85410f307ccf0e8acf480082930a5))

## v4.1.1

### 13 Feb 2020 — 17:36:32 UTC

#### other

* **\*:** chore: Use forgeboxStorage ([7ac6965](https://github.com/coldbox-modules/cbauth/commit/7ac6965013b3a08c027d85f4b0700e3d4ac75930))

## v4.1.0

### 23 Dec 2019 — 18:06:36 UTC

#### feat

* **Login:** Add new `preLogin` and `postLogin` interception points ([495d516](https://github.com/coldbox-modules/cbauth/commit/495d516b09e126ab92fac1423958ce8adaeb3be7))

## v4.0.0

### 02 Oct 2019 — 05:29:36 UTC

#### BREAKING

* **cbstorages:** Upgrade cbstorages to 2.0.0 ([10b3156](https://github.com/coldbox-modules/cbauth/commit/10b3156b3861c97ae7f87c53377db00226abe5e9))

## v3.0.3

### 24 Sep 2019 — 16:40:21 UTC

#### other

* **\*:** chore: Transfer cbauth to coldbox-modules namespace ([2616896](https://github.com/coldbox-modules/cbauth/commit/26168963563d25accb007fb274c95416938b6baf))

## v3.0.2

### 22 Sep 2019 — 19:08:45 UTC

#### other

* **\*:** docs: Fixed Coldbox 4.3 docs link ([d4252ce](https://github.com/elpete/cbauth/commit/d4252cee40997d2e2747082791be0498072374eb))

## v3.0.1

### 22 Sep 2019 — 18:58:14 UTC

#### chore

* **build:** Use openjdk8 on Travis ([0ba288b](https://github.com/elpete/cbauth/commit/0ba288b7c8e89320eb33b9dfc08d3e1237a6a4c3))

## v3.0.0

### 12 Jul 2019 — 20:14:17 UTC

#### BREAKING

* **Storages:** Allow customizing of storages ([b97a8ad](https://github.com/elpete/cbauth/commit/b97a8adfd90fdace338a516d383750152dbe3d61))

## v2.0.0

### 25 Oct 2018 — 06:56:50 UTC

#### BREAKING

* **build:** Trigger major release for prior commit ([fca4bc5](https://github.com/elpete/cbauth/commit/fca4bc5bba38026a10c689f0c0ad21bc7a7d2211))

#### chore

* **ci:** Add commandbox-semantic-release ([d9a0411](https://github.com/elpete/cbauth/commit/d9a0411e471f39f91f14fc17d68acc8f57a4be3a))
* **formatting:** Clean up spacing at end of lines ([ba8f1d3](https://github.com/elpete/cbauth/commit/ba8f1d375a4d5b6460833203c80e044123e5633f))
* **server.json:** Default to adobe\@11 servers ([a73da29](https://github.com/elpete/cbauth/commit/a73da292232ca14db844d42010e57120a1435a49))
* **tests:** Remove Gulpfile and npm dependencies ([031a697](https://github.com/elpete/cbauth/commit/031a6978dfe33cedcceba7a2d81420bf4b759d88))

#### fix

* **build:** Update box.json references to elpete ([76e416e](https://github.com/elpete/cbauth/commit/76e416ed099892494d0f849621fdb75fa9dfd3f0))
* **build:** Remove incompatible scripts for commandbox-semantic-release ([252db7e](https://github.com/elpete/cbauth/commit/252db7e6f65623b7a77a59c152dfdfcbe76548f2))
* **tests:** Fix MockBox expectation to match struct pattern ([2e5fe23](https://github.com/elpete/cbauth/commit/2e5fe23fc764612c35e572883ec655f7ef195759))

#### other

* **\*:** Merge pull request #3 from elpete/add\_csr ([74c4f63](https://github.com/elpete/cbauth/commit/74c4f63a97d4b3d98b28b5a729595c353b159d3e))
* **\*:** Merge pull request #2 from jclausen/master ([8c71db8](https://github.com/elpete/cbauth/commit/8c71db88efc70eec1fdc72679fef493ad5998d22))

## v2.0.0

### 25 Oct 2018 — 06:40:06 UTC

#### BREAKING

* **build:** Trigger major release for prior commit ([fca4bc5](https://github.com/octanner/cbauth/commit/fca4bc5bba38026a10c689f0c0ad21bc7a7d2211))

#### chore

* **ci:** Add commandbox-semantic-release ([d9a0411](https://github.com/octanner/cbauth/commit/d9a0411e471f39f91f14fc17d68acc8f57a4be3a))
* **formatting:** Clean up spacing at end of lines ([ba8f1d3](https://github.com/octanner/cbauth/commit/ba8f1d375a4d5b6460833203c80e044123e5633f))
* **server.json:** Default to adobe\@11 servers ([a73da29](https://github.com/octanner/cbauth/commit/a73da292232ca14db844d42010e57120a1435a49))
* **tests:** Remove Gulpfile and npm dependencies ([031a697](https://github.com/octanner/cbauth/commit/031a6978dfe33cedcceba7a2d81420bf4b759d88))

#### fix

* **build:** Remove incompatible scripts for commandbox-semantic-release ([252db7e](https://github.com/octanner/cbauth/commit/252db7e6f65623b7a77a59c152dfdfcbe76548f2))
* **tests:** Fix MockBox expectation to match struct pattern ([2e5fe23](https://github.com/octanner/cbauth/commit/2e5fe23fc764612c35e572883ec655f7ef195759))

#### other

* **\*:** Merge pull request #3 from elpete/add\_csr ([74c4f63](https://github.com/octanner/cbauth/commit/74c4f63a97d4b3d98b28b5a729595c353b159d3e))
* **\*:** Merge pull request #2 from jclausen/master ([8c71db8](https://github.com/octanner/cbauth/commit/8c71db88efc70eec1fdc72679fef493ad5998d22))


# Installation and Usage

## Requirements

* Lucee 5+
* Adobe ColdFusion 2016+
* Coldbox 4.3 +

## Installation

`cbauth` requires ColdBox 4.3 or higher for [module parent settings](https://github.com/ortus-docs/coldbox-docs/blob/v4.x/intro/introduction/whats-new-with-4.3.0.md).

`cbauth` can be installed with

```bash
box install cbauth
```

## Configuration

cbauth needs a `userServiceClass` which has to be specified in the module settings. It should be a WireBox mapping that resolves to a component that implements the `IUserService` interface (though this implementation can be implicit.)

By default, cbauth uses `sessionStorage@cbstorages` and `RequestStorage@cbstorages` for the `sessionStorage` and `requestStorage`, respectively.

Your config settings will look like this:

```javascript
	moduleSettings = {
			cbauth: {
				userServiceClass: "UserService",
				// optional, override when needed
				sessionStorage: "SessionStorage@cbstorages",
				requestStorage: "RequestStorage@cbstorages"
			},
			//..... other module settings 
	}
```

You can specify other `requestStorage` or `sessionStorage` (e.g distributed cache) as long as your new storages follow the Interface definitions as defined:

```javascript
interface name="SessionStorageInterface" { // or "RequestStorageInterface"
	  public any function getVar( required string name, any defaultValue );
	  public void function setVar( required string name, required any value );
	  public boolean function deleteVar( required string name );
	  public boolean function exists( required string name );
}
```

{% hint style="info" %}
You don't have to formally implement the interface in your code.
{% endhint %}

## Usage

Before you can use `cbauth` you have to create a `UserService` which implement the [IUserService](/iuserservice).

```javascript
interface {

	/**
	 * Verify if the incoming username/password are valid credentials.
	 *
	 * @username The username
	 * @password The password
	 */
	boolean function isValidCredentials( required username, required password );

	/**
	 * Retrieve a user by username
	 *
	 * @return User that implements IAuthUser
	 */
	function retrieveUserByUsername( required username );

	/**
	 * Retrieve a user by unique identifier
	 *
	 * @id The unique identifier
	 *
	 * @return User that implements IAuthUser
	 */
	function retrieveUserById( required id );
	
}
```

You also have a User class which implements the [IauthUser](/iauthuser) interface.

```javascript
interface {

    /**
     * Return the unique identifier for the user
     */
    function getId();

}
```

{% hint style="danger" %}
If you use `cbauth` combined with [`cbsecurity`](https://coldbox-security.ortusbooks.com/usage/authentication-services#user-interface) or [`cbguard`](https://www.forgebox.io/view/cbguard) there are some additional method requirements for the User. Please check the corresponding docs for details.
{% endhint %}

When you have create your `User` and `UserService` and configured the `moduleSettings` you are ready to use the `AuthenticationService`. You can inject the authentication service using WireBox:

```javascript
property name="auth" inject="authenticationService@cbauth";

// OR

var auth = wirebox.getInstance( "authenticationService@cbauth" );
```

Or, the quick way, you can just use the `auth()` helper method (which is actually just a shortcut to a wirebox injection). The `auth()` helper is very useful in views. And since Wirebox handles singleton management, you don't have to worry about calling `auth()`too many times.

{% hint style="success" %}
The `auth()` helper is available in handlers, layouts, and views. You will need to use the injection if you need cbauth in other models.
{% endhint %}

The Authentication service provides you with all methods for handling user sessions, e.g:

```javascript
auth.authenticate( username, password );
auth.isLoggedIn();
auth.getUser();
auth.logout();
```

After login your userID is stored in sessionstorage. Your user object will be cached in the requeststorage, so you only have to hit your database once per request to access user information.

The full list of methods is described in the [Authentication Service](/authentication-service) section.


# Authentication Service

The authentication service can be used by injecting it using WireBox:

```javascript
property name="auth" inject="authenticationService@cbauth";

// OR

var auth = wirebox.getInstance( "authenticationService@cbauth" );
```

Or, the quick way, you can just use the `auth()` helper method (which is actually just a shortcut to a wirebox injection). The `auth()` helper is very useful in views. And since Wirebox handles singleton management, you don't have to worry about calling `auth()`too many times.

{% hint style="success" %}
The `auth()` helper is available in handlers, layouts, and views.  You will need to use the injection if you need cbauth in other models.
{% endhint %}

## Methods

### login

| argument | type | required | default | description                                                                       |
| -------- | ---- | -------- | ------- | --------------------------------------------------------------------------------- |
| user     | any  | `true`   |         | The user component to log in. The component must respond to the `getId()` method. |

Logs a user in to the system. The returned user component must respond to the `getId()` method (as defined in the [`IAuthUser`](/iauthuser) interface). Additionally, the user is cached in the `request` scope. If a user is already in the session, this will replace it with the given user. This method returns the passed in `user` object.

### logout

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| No arguments |      |          |         |             |

Logs a user out of system. This method can be called regardless of if there is currently a logged in user.

### authenticate

| argument | type   | required | default | description                        |
| -------- | ------ | -------- | ------- | ---------------------------------- |
| username | string | `true`   |         | The username to attempt to log in. |
| password | string | `true`   |         | The password to attempt to log in. |

Attempts to log a user by calling the `retrieveUserByUsername` and `isValidCredentials` on the provided `userServiceClass`. If `isValidCredentials` returns `false`, it throws a `InvalidCredentials` exception.

If it succeeds, it returns the logged in `user` object. If it succeeds, it also sets the user id (obtained by calling `getId()` on the returned user component) in the configured `sessionStorage` and the returned user component in the configured `requestStorage`.

### isLoggedIn

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| no arguments |      |          |         |             |

Returns `boolean` whether a user is logged in to the system.&#x20;

### check

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| no arguments |      |          |         |             |

Alias for `isLoggedIn`

### guest

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| no arguments |      |          |         |             |

Returns whether a user is logged out of the system.  Opposite of `check()` and `isLoggedIn()`.

### getUser

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| no arguments |      |          |         |             |

Returns the currently logged in user component.

If there is no logged in user, it throws a `NoUserLoggedIn` exception.

If there is a user object in the configured `requestStorage`, it is returned.

If the user object has not been fetched this request, it uses the id set in the configured `sessionStorage` to fetch the user (using `retrieveUserById`). It then sets the user in the configured `requestStorage` so subsequent calls to `getUser` don't re-fetch the user.

### user

| argument     | type | required | default | description |
| ------------ | ---- | -------- | ------- | ----------- |
| no arguments |      |          |         |             |

Alias for `getUser`

### getUserId

| argument | type | required | default | description |
| -------- | ---- | -------- | ------- | ----------- |
|          |      |          |         |             |

Returns the currently logged in user id.

If there is no logged in user, it throws a `NoUserLoggedIn` exception.


# IUserService

You have to create a `UserService` and [specify a `userServiceClass` in your `moduleSettings`](/installation-and-usage#configuration).  This  `UserService` needs to have three methods, according to `cbauth.interfaces.IUserService`

```javascript
interface {

	/**
	 * Verify if the incoming username/password are valid credentials.
	 *
	 * @username The username
	 * @password The password
	 */
	boolean function isValidCredentials( required username, required password );

	/**
	 * Retrieve a user by username
	 *
	 * @return User that implements IAuthUser
	 */
	function retrieveUserByUsername( required username );

	/**
	 * Retrieve a user by unique identifier
	 *
	 * @id The unique identifier
	 *
	 * @return User that implements IAuthUser
	 */
	function retrieveUserById( required id );
}
```

{% hint style="info" %}
If you want to implement a `UserService` for `cbauth` combined with `cbsecurity` you will find your interface specification in [`cbsecurity.interfaces.IUserService`](https://coldbox-security.ortusbooks.com/usage/authentication-services#authentication-service-interface).  Methods in this spec are equal.
{% endhint %}

The user component returned by both `retrieve...` methods needs to respond to `getId()` as specified by the [IAuthUser](/iauthuser) interface.&#x20;

{% hint style="warning" %}
Combined with [`cbsecurity`](https://coldbox-security.ortusbooks.com/usage/authentication-services#authentication-service-interface) or [`cbguard`](https://www.forgebox.io/view/cbguard) you might have to specify additional methods for checking roles or permissions.
{% endhint %}


# IAuthUser

You have to create a User component which responds to the `getId()` method. This user will be retrieved by the retrieve methods from your [`IUserService`](/iuserservice)

```javascript
interface {

    /**
     * Return the unique identifier for the user
     */
    function getId();

    /**
     * Verify if the user has one or more of the passed in permissions
     *
     * @permission One or a list of permissions to check for access
     *
     */
    boolean function hasPermission( required permission );

    /**
     * Shortcut to verify it the user is logged in or not.
     */
    boolean function isLoggedIn();

}
```

{% hint style="warning" %}
Combined with [`cbsecurity`](https://coldbox-security.ortusbooks.com/usage/authentication-services#user-interface) or [`cbguard`](https://www.forgebox.io/view/cbguard) you might have to specify additional methods for checking roles or permissions.
{% endhint %}


# Customization Options

`cbauth` is quite flexible. In your `IUserService` implementation you can define how you want to retrieve your `IAuthUser` implementation: from a database, LDAP or any other authentication provider. You can define any properties you want to store, permissions or roles, and additional data for your authenticated user.  &#x20;

The current user will be retrieved and cached in a configured `requestStorage`. The userID will be stored in a configured `sessionStorage`.  Both `sessionStorage` and `requestStorage` can be anything you want, as long as they implement the required methods. A common scenario, for example, is when you don't want to use ColdFusion or Lucee sessions for API applications, but instead use a distributed cache.

```javascript
interface name="SessionStorageInterface" { // or "RequestStorageInterface"
	  public any function getVar( required string name, any defaultValue );
    public void function setVar( required string name, required any value );
	  public boolean function deleteVar( required string name );
	  public boolean function exists( required string name );
}
```

Additional information for your user can be stored after authentication in your sessio- or request storage by using the [interception points](/interception-points) announced by cbauth.


# Interception points

## Interceptions

`cbauth` announces several custom interception points. You can use these interception points to change request data or add additional values to session or request scopes. The `preAuthentication` and `postAuthentication` events fire during the standard `authenticate()` method call with a username and password. The `preLogin` and `postLogin` events fire during the `login()` method call. The `preLogout` and `postLogout` events fire during the `logout()` method call.

{% hint style="info" %}
the `preLogin` and `postLogin` interception points will be called during the course of `authenticate()`. The order of the calls then are `preAuthentication` -> `preLogin` -> `postLogin` -> `postAuthentication`.
{% endhint %}

### preAuthentication

**InterceptData**

| Name     | Description                        |
| -------- | ---------------------------------- |
| username | The username passed in to `cbauth` |
| password | The password passed in to `cbauth` |

Modifying the values in the `interceptData` will change what is passed to `isValidCredentials` and `retrieveUserByUsername`. This is the prime time to ignore certain requests or remove or pad usernames.

### postAuthentication

**InterceptData**

| **Name**       | Description                                                    |
| -------------- | -------------------------------------------------------------- |
| user           | The user component to be logged in                             |
| sessionStorage | The sessionStorage object to store additional values if needed |
| requestStorage | The requestStorage object to store additional values if needed |

This is the prime time to store additional values based on the user returned.

### preLogin

**InterceptData**

| **Name** | Description                        |
| -------- | ---------------------------------- |
| user     | The user component to be logged in |

### postLogin

**InterceptData**

| **Name**       | Description                                                    |
| -------------- | -------------------------------------------------------------- |
| user           | The user component to be logged in.                            |
| sessionStorage | The sessionStorage object to store additional values if needed |
| requestStorage | The requestStorage object to store additional values if needed |

This is a good opportunity to store additional data if your application logged the user in manually without authenticating via a username/password like a "remember me" system.

### preLogout

**InterceptData**

| **Name** | Description                         |
| -------- | ----------------------------------- |
| user     | The user component to be logged in. |

### postLogout

InterceptData

| Name               | Description |
| ------------------ | ----------- |
| no additional data |             |


