# django-cognito-saml

Library to implement django authentication using cognito (via pyjwt).

Assumptions made:

- Using `authorization code` flow. Implicit grant is insecure as the access token is transferred over in the request parameters without encryption.

## Settings

The following settings should be set in your settings file against a `COGNITO_CONFIG` dictionary.

| Setting           | Description                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **ENDPOINT**      | Either the hosted domain or custom domain for your cognito app                                                               |
| **CLIENT_ID**     | CLIENT_ID of your application in your user pool                                                                              |
| **CLIENT_SECRET** | CLIENT_SECRET of your application in your user pool                                                                          |
| **JWKS_URI**      | The JWKS URI of your user pool. Used to verify the JWT.                                                                      |
| **REDIRECT_URI**  | **OPTIONAL** It is possible to share one cognito app with multiple websites via a proxy.                                     |
| **RESPONSE_HOOK** | **OPTIONAL** Post authentication hook to modify the response (perhaps to add headers). Specify it as a django import_string. |

## Installation

1. Add the above settings to your settings.

```settings.py
COGNITO_CONFIG = {
    "ENDPOINT": "",
    "CLIENT_ID": "",
    "CLIENT_SECRET": "",
    "JWKS_URI": "",
    "REDIRECT_URI": "",
    "RESPONSE_HOOK": ""
}
```

2. Define your authentication backend. Subclass off `django_cognito_saml.backends.CognitoUserBackend`.

   Define the `username` field of your user by customizing the `authenticate` method. If you wish
   to add additional fields to the user or modify the user's permissions, override the `configure_user`
   method. The `configure_user` method has access to `self.cognito_jwt` which contains the decoded
   jwt token with the cognito saml assertions.

   Set `create_unknown_user = False` if you want to disable automatic creation of users.

```python
class CustomCognitoBackend(CognitoUserBackend):
    # Change this to False if you do not want to create a remote user.
    create_unknown_user = True

    def authenticate(  # type: ignore[override]
        self, request: HttpRequest, cognito_jwt: dict[str, Any], **kwargs: Any
    ) -> Optional[AbstractBaseUser]:
        # Customizing the username field used to create the user
        remote_user = cognito_jwt["username"]
        user = super().authenticate(request, remote_user=remote_user, **kwargs)
        return user

    def configure_user(  # type: ignore[override]
        self, request: HttpRequest, user: AbstractBaseUser, created: bool = True
    ) -> AbstractBaseUser:
        # Configuring the user post login
        if created:
            user.name = self.cognito_jwt["name"]
            user.save()
        return user


```

3. Add `CustomCognitoBackend` to your authentication backends.

```python
AUTHENTICATION_BACKENDS = (
    ...
    "apps.backends.CustomCognitoBackend",
    ...
)
```

4. Add the cognito saml urls to your `urls.py`

```python
urls = [
    ...
    path("/", include("django_cognito_saml.urls")),
]
```
