# Activeconnect

[Activeconnect](https://activeconnect.io) provides multifactor identity and presence verification.


This library provides a Python wrapper for the Activeconnect API.

## Getting Started
### Create an Activeconnect Account
To begin visit [Activeconnect Developer Portal](https://activeconnect.activeapi.ninja/register) to register.
### Create an Activeconnect Application
Once you have registered [create a new Activeconnect application](https://activeconnect.activeapi.ninja/create_application).
Save the Application ID and Application Secret in a safe place as you will need this to authenticate calls to the Activeconnect API.
### Register Users
Activeconnect identifies application users using a token supplied by the application developer.
You can use your existing user IDs or create a lookup table that maps your user ID to a value you provide to Activeconnect.

Users are registered using the Activeconnect ManagementAPI.
Create an instance of Activeconnect.ManagementAPI using your application ID and secret.
```python
from Activeconnect.management_api import ManagementAPI
from Activeconnect.management_api import ManagementAPIResult
application_id = "MY APPLICATION ID"
application_secret = "MY APPLICATION SECRET"

manager = ManagementAPI(application_id="MY APPLICATION ID", application_secret="MY APPLICATION SECRET")
```
To add a single user call ManagementAPI.add_user
```python
add_user_result = manager.add_user("MY USER")

if add_user_result == ManagementAPIResult.success:
    # User added
    print("user added")
elif add_user_result == ManagementAPIResult.user_exists:
    # User already exists
    print("user already exists")
else:
    # User failed
    print("add user failed")
```
To add multiple users call ManagementAPI.add_users.
```python
users = ["MY USER 1", "MY USER 2", "MY USER 3"]
created, existing = manager.add_users(users)
if created is not None:
    print("Users created: {}".format(created))
if existing is not None:
    print("Existing users: {}".format(existing))
``` 
### Registering a Mobile Device
Activeconnect uses a mobile device to collect authentication data.
Mobile devices are registered using a registration link generated by Activeconnect.
The Activeconnect mobile application is registered to open these links and register the device.
To obtain a registration link use ManagementAPI.get_registration_link.
The display_name query parameter is optional and is used by the Activeconnect mobile app to provide a description of the user.
```python
registration_link = manager.get_registration_link(user_id="MY USER 1", display_name="MY USER 1@myapp")
```
ManagementAPI also provides a helper method to send a registration link to a mobile device using SMS.
```python
manager.send_registration_sms(  user_id="MY USER 1",
                                display_name="MY USER1@myapp",
                                phone_number="+1XXXYYYY",
                                message=None)
```
You can specify a message for the SMS body
```python
manager.send_registration_sms(  user_id="MY USER 1",
                                display_name="MY USER1@myapp",
                                phone_number="+1XXXYYYY",
                                message="REGISTER FOR MY APP")
```
### Registering a Mobile Device
Before a user can authenticate using Activeconnect they must register a mobile device.
To check if a user has registered a mobile device use ManagementAPI.has_registered_mobile_device
```python
has_device = manager.has_registered_mobile_device("MY USER 1")

if has_device is ManagementAPIResult.has_mobile_device:
    print("User has mobile device.")
elif has_device is ManagementAPIResult.no_mobile_device:
    print("User has no mobile device.")
else:
    print("has_registered_mobile_device failed.")
```
### Removing Users
To remove a single user use ManagementAPI.delete_user
```python
manager.delete_use("MY USER 1")
```
To remove multiple users use ManagementAPI.delete_users
```python
users=["MY USER 1", "MY USER 2",...]
manager.delete_users(users)
```

### Authenticating Users
Activeconnect authentication is a multi step process:
* Initiate the authentication process using the Authentication API.
* If the process is initiated the mobile device will collect authentication data and send it to Activeconnect
* Activeconnect processes the collected data and determines whether the user is authenticated.
Create an instance of Activeconnect.AuthenticationAPI using the application ID and application secret created above.
```python
from Activeconnect.authentication_api import AuthenticationAPI,AuthenticationMethod
authenticator=AuthenticationAPI(application_id="MY APPLICATION ID", 
                                application_secret="MY APPLICATION SECRET")

# Initiate the authentication process.
session = authenticator.authenticate_user("MY USER 1")

# Check if authentication started.
if session.failed:
    # Authentication failed - check the failure reason.
    # If the user has not registered a mobile device, the failure_reason will be NO_MOBILE_DEVICE
    print("Authentication failed {}".format(session.failure_reason))
elif session.in_progress:
    # Authentication is in progress
    print("Authentication in progress")
else:
    print("Session status is {}".format(session.session_status.name))
```
Once the authentication process is initiated periodically check the status of the session using Activeconnect.Session.getStatus.
```python
# Wait for the user to approve the request.
while session.in_progress:
    # Get the status of the session
    session_status = session.get_status()
    
    # Wait a while and try again
    time.sleep(5)

if session.active:
    print("authenticated")
    # Now end the session
    session.destroy()
else:
    print("Authentication failed {}".format(session.session_status.name))
```
### Ending a Session
To end an Activeconnect session call Activeconnect.Session.destroy.
```python
session.destroy()
```
### Session Serialization
It may be necessary to save session information in cookies or pass session information with URLS.
Activeconnect.Session is derived from [marshmallow dataclass](https://pypi.org/project/marshmallow-dataclass/) and can be serialized as JSON.
```python
# Save a session as JSON
session_json=Session.Schema().dumps(session)

# Load a session from JSON
new_session=Session.Schema().loads(session_json)
```
It is recommeded that the generated JSON in encrypted before storing.
One way to do this is to use [the itsdangerous package](https://pypi.org/project/itsdangerous/).
```python
from itsdangerous.url_safe import URLSafeSerializer

# Convert the session to JSON.
session_json=Session.Schema().dumps(session)

# Encode/encrypt the session JSON
s = URLSafeSerializer("secret-key")
session_token = s.dumps(session_json)

# Store the session_token...
```