Metadata-Version: 2.4
Name: takegroup-auth
Version: 0.2.0
Summary: Reusable Google Workspace authentication helpers for internal Django apps.
Author: Takegroup
License: Private
Requires-Python: >=3.10
Requires-Dist: cryptography>=42
Requires-Dist: django-allauth>=0.63
Requires-Dist: django>=4.2
Requires-Dist: pyjwt>=2.8
Requires-Dist: requests>=2.31
Provides-Extra: test
Requires-Dist: pytest-django>=4.8; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Description-Content-Type: text/markdown

# Takegroup Google Auth

Private Django package for Google Workspace-only authentication in internal apps.

It relies on `django-allauth` for OAuth/OIDC and adds a small adapter that:

- accepts only Google logins with a trusted Workspace `hd` claim;
- requires verified Google email addresses;
- connects an existing Django user by email when present;
- creates a normal non-staff Django user when no user exists;
- updates email, first name, and last name on later logins.

The Workspace domain defaults to `takegroup.pl`.

## Install

```bash
pip install "takegroup-auth @ git+ssh://git@github.com/Take-Group/takegroup-auth.git@main"
```

For requirements files:

```text
takegroup-auth @ git+ssh://git@github.com/Take-Group/takegroup-auth.git@main
```

For production, prefer installing a tagged release instead of `main`:

```text
takegroup-auth @ git+ssh://git@github.com/Take-Group/takegroup-auth.git@v0.1.0
```

Because this is a private GitHub repository, the installing environment must have read access. For servers, Docker builds, and CI jobs, use a read-only SSH key, GitHub App, machine-user SSH key, or fine-grained PAT stored as a secret.

Railway Docker builds should use a build variable named `TAKEGROUP_AUTH_DEPLOY_KEY` that contains a read-only private deploy key for this repository. This matches Dropomat's production setup and works when Railway provides secrets as build variables:

```Dockerfile
# syntax=docker/dockerfile:1.7

FROM python:3.12-slim AS python-deps

ARG TAKEGROUP_AUTH_DEPLOY_KEY

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
    git openssh-client \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN mkdir -p ~/.ssh && \
    chmod 700 ~/.ssh && \
    ssh-keyscan github.com >> ~/.ssh/known_hosts && \
    python -c 'import os; from pathlib import Path; key = os.environ.get("TAKEGROUP_AUTH_DEPLOY_KEY", "").replace("\\n", "\n"); path = Path("/root/.ssh/takegroup_auth"); path.write_text(key.rstrip("\n") + "\n") if key else None' && \
    if [ -f ~/.ssh/takegroup_auth ]; then chmod 600 ~/.ssh/takegroup_auth && printf '%s\n' "Host github.com" "  IdentityFile ~/.ssh/takegroup_auth" "  IdentitiesOnly yes" > ~/.ssh/config; fi && \
    pip install --default-timeout=120 --retries 10 --no-cache-dir -r requirements.txt && \
    rm -f ~/.ssh/takegroup_auth ~/.ssh/config

FROM python:3.12-slim

WORKDIR /app
COPY --from=python-deps /usr/local /usr/local
COPY . .
```

Set `TAKEGROUP_AUTH_DEPLOY_KEY` in Railway as either the multiline private key or with newlines escaped as `\n`. Keep the `takegroup-auth` requirements entry as an SSH URL:

```text
takegroup-auth @ git+ssh://git@github.com/Take-Group/takegroup-auth.git@v0.1.0
```

Example GitHub Actions SSH setup when `TAKEGROUP_AUTH_DEPLOY_KEY` contains a private read-only key:

```yaml
- name: Configure SSH for private dependencies
  run: |
    mkdir -p ~/.ssh
    echo "${{ secrets.TAKEGROUP_AUTH_DEPLOY_KEY }}" > ~/.ssh/takegroup_auth
    chmod 600 ~/.ssh/takegroup_auth
    ssh-keyscan github.com >> ~/.ssh/known_hosts
    cat > ~/.ssh/config <<EOF
    Host github.com
      IdentityFile ~/.ssh/takegroup_auth
      IdentitiesOnly yes
    EOF

- name: Install dependencies
  run: pip install -r requirements.txt
```

For local Docker builds outside Railway, BuildKit SSH forwarding also works:

```Dockerfile
# syntax=docker/dockerfile:1.7

FROM python:3.12-slim

RUN apt-get update && apt-get install -y git openssh-client && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY requirements.txt .

RUN --mount=type=ssh \
    mkdir -p ~/.ssh && \
    ssh-keyscan github.com >> ~/.ssh/known_hosts && \
    pip install -r requirements.txt
```

Build with:

```bash
DOCKER_BUILDKIT=1 docker build --ssh default -t my-app .
```

HTTPS with a secret token also works:

```text
takegroup-auth @ git+https://${GITHUB_TOKEN}@github.com/Take-Group/takegroup-auth.git@v0.1.0
```

## Django Setup

```python
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "django.contrib.sites",
    "allauth",
    "allauth.account",
    "allauth.socialaccount",
    "allauth.socialaccount.providers.google",
    "takegroup_auth",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "allauth.account.middleware.AccountMiddleware",
]

AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend",
]

SITE_ID = 1
SOCIALACCOUNT_ADAPTER = "takegroup_auth.adapter.InternalGoogleSocialAccountAdapter"
SOCIALACCOUNT_PROVIDERS = {
    "google": {
        "SCOPE": ["profile", "email", "openid"],
        "AUTH_PARAMS": {"hd": "takegroup.pl"},
    }
}

LOGIN_URL = "/auth/google/login"
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/login/"
```

If the project defines `TEMPLATES["OPTIONS"]["context_processors"]`, make sure this is present:

```python
"django.template.context_processors.request"
```

Include allauth URLs:

```python
urlpatterns = [
    path("", include("takegroup_auth.urls")),
]
```

Run:

```bash
python manage.py migrate
python manage.py check
```

Configure the Google `SocialApp` in Django admin, or set it up in the host app's deployment process.

For step-by-step agent instructions, see `INTEGRATE_TAKEGROUP_AUTH.md`.

## Google Secret JSON

Instead of configuring the Google `SocialApp` in Django admin, you can pass the OAuth client secret JSON into settings:

```python
import os

from takegroup_auth.env import settings_from_env

globals().update(
    settings_from_env(
        {
            "GOOGLE_OAUTH_CLIENT_SECRET_JSON": os.environ["GOOGLE_OAUTH_CLIENT_SECRET_JSON"],
        }
    )
)
```

Or pass a file path:

```python
from takegroup_auth.env import settings_from_env

globals().update(
    settings_from_env(
        {
            "GOOGLE_OAUTH_CLIENT_SECRET_FILE": "/run/secrets/google-oauth-client.json",
        }
    )
)
```

This fills:

```python
INTERNAL_AUTH_GOOGLE_DOMAIN = "takegroup.pl"
SOCIALACCOUNT_PROVIDERS = {
    "google": {
        "SCOPE": ["profile", "email", "openid"],
        "AUTH_PARAMS": {"hd": "takegroup.pl"},
        "APP": {
            "name": "Takegroup Google OAuth",
            "client_id": "...",
            "secret": "...",
        },
    }
}
```

## Template Integration

The package ships a full fallback login page at:

```text
internal_auth/login.html
```

Projects can also include smaller partials inside their own pages.

Button only:

```django
{% include "internal_auth/google_signin_button.html" with internal_auth_button_class="btn btn-primary" internal_auth_button_text="Continue with Google" %}
```

Small card:

```django
{% include "internal_auth/google_signin_card.html" with internal_auth_card_class="auth-card" internal_auth_button_class="btn btn-primary" %}
```

The card uses CSS variables, so projects can style it through a wrapper class:

```css
.auth-card {
  --tg-auth-surface: var(--panel-bg);
  --tg-auth-text: var(--text);
  --tg-auth-muted: var(--muted);
  --tg-auth-border: var(--border);
  --tg-auth-button-bg: var(--brand);
  --tg-auth-button-bg-hover: var(--brand-hover);
  --tg-auth-button-text: #fff;
  --tg-auth-focus: var(--brand);
}
```

Or pass server-controlled inline style values:

```django
{% include "internal_auth/google_signin_card.html" with internal_auth_card_style="--tg-auth-button-bg: #0055cc;" %}
```

Supported context variables:

```text
internal_auth_card_class
internal_auth_card_style
internal_auth_title_class
internal_auth_subtitle_class
internal_auth_card_title
internal_auth_card_subtitle
internal_auth_form_class
internal_auth_form_style
internal_auth_button_class
internal_auth_button_style
internal_auth_button_text
```

For full control, create templates with the same paths in the host project, for example:

```text
templates/internal_auth/login.html
templates/internal_auth/google_signin_card.html
templates/internal_auth/google_signin_button.html
```

Configure Google OAuth redirect URI as:

```text
https://your-app.example.com/auth/google/callback
```
