Skip to content

Access Tokens

Guide to configuring GitLab access tokens for GitPulse.

Types of tokens

graph TB
    subgraph "GitLab Tokens"
        PAT["Personal Access Token"]
        GAT["Group Access Token"]
        PAT2["Project Access Token"]
        OAUTH["OAuth2 Token"]
    end

    PAT --> |"Suitable for"| DEV["Development"]
    GAT --> |"Suitable for"| PROD["Production"]
    PAT2 --> |"Suitable for"| SINGLE["Single project"]
    OAUTH --> |"Suitable for"| USER["User context"]
Type Using Scope Lifetime
Personal Access Token Development User-level Configurable
Group Access Token Production Group-level Max 1 year
Project Access Token Single project Project-level Max 1 year
OAuth2 Token User auth User-level Short-lived

Personal Access Token

Creation

  1. Sign in to GitLab
  2. Click on avatar -> Preferences
  3. In the left menu: Access Tokens
  4. Fill in:
  5. Token name: GitPulse Production or GitPulse Development
  6. Expiration date: Max 1 year (365 days)
  7. Scopes: See below

Required scopes

Text Only
1
2
3
4
5
Yes api           - Full API access
Yes read_api      - Read-only API access
Yes read_user     - Read user info
Yes read_repository - Clone/fetch repositories
□ write_repository - Push (not needed)

Minimum privilege

For production, use only the minimum required permissions. For read-only access, the following are sufficient: read_api, read_repository.

An example

Bash
1
2
3
4
5
6
# Token looks like this:
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

# Test the token
curl -H "Private-Token: ${GITLAB_TOKEN}" \
  "https://gitlab.kpi.tuke.sk/api/v4/user"

Group Access Token

For production deployment, we recommend Group Access Token.

Creation

  1. Go to GitLab Group (eg /kpi/tp-2024)
  2. Settings -> Access Tokens
  3. Fill in:
  4. Token name: GitPulse Sync Token
  5. Expiration date: End of semester
  6. Role: Reporter or Developer
  7. Scopes: api, read_repository

Advantages

  • It is not tied to a specific user
  • It works even if the user leaves
  • More granular scope control
  • Audit log at group level

Project Access Token

For single-project integration:

Bash
# At the project level: Settings -> Access Tokens
# Create a token with the Reporter role and read_api scope

Configuration in GitPulse

Environment variables

Bash
1
2
3
4
5
6
7
8
9
# .env
GITLAB_URL=https://gitlab.kpi.tuke.sk
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

# For multiple instances (advanced)
GITLAB_TOKENS='[
  {"name": "primary", "token": "glpat-xxx", "url": "https://gitlab.kpi.tuke.sk"},
  {"name": "backup", "token": "glpat-yyy", "url": "https://gitlab.example.com"}
]'

Docker secrets (production)

YAML
# docker-compose.yml
services:
  api:
    secrets:
      - gitlab_token
    environment:
      GITLAB_TOKEN_FILE: /run/secrets/gitlab_token

secrets:
  gitlab_token:
    file: ./secrets/gitlab_token.txt
Bash
1
2
3
4
# Create the secret file
mkdir -p secrets
echo "glpat-xxxxxxxxxxxxxxxxxxxx" > secrets/gitlab_token.txt
chmod 600 secrets/gitlab_token.txt

Token rotation

Automatic notification

Python
# Monitoring token expiration
from datetime import datetime, timedelta

def check_token_expiry(token_info: dict) -> bool:
    expiry = datetime.fromisoformat(token_info['expires_at'])
    warning_threshold = datetime.now() + timedelta(days=30)

    if expiry < warning_threshold:
        send_alert(f"Token expires in {(expiry - datetime.now()).days} days")
        return True
    return False

Manual rotation

Bash
# 1. Create a new token (see above)

# 2. Update .env
nano .env
# Change GITLAB_TOKEN to the new one

# 3. Restart services
docker compose restart api worker

# 4. Verify functionality
curl http://localhost:8000/api/v1/health

# 5. Revoke the old token in GitLab UI

Zero-downtime rotation

Bash
# 1. Add the new token as secondary
GITLAB_TOKEN_NEW=glpat-newtoken

# 2. Update configuration to use both
# (application tries primary, then fallback)

# 3. Switch to the new one as primary
GITLAB_TOKEN=${GITLAB_TOKEN_NEW}

# 4. Remove the old one

Troubleshooting

The token does not work

Bash
1
2
3
4
5
6
7
# Test basic access
curl -I -H "Private-Token: ${GITLAB_TOKEN}" \
  "https://gitlab.kpi.tuke.sk/api/v4/user"

# Expected response: HTTP 200
# If 401: Token is invalid or expired
# If 403: Insufficient permissions

Rate limiting

Bash
1
2
3
4
5
6
7
# Check rate limit headers
curl -i -H "Private-Token: ${GITLAB_TOKEN}" \
  "https://gitlab.kpi.tuke.sk/api/v4/projects" | head -20

# RateLimit-Limit: 600
# RateLimit-Remaining: 599
# RateLimit-Reset: 1699999999

Scope problems

Bash
1
2
3
4
5
6
7
# Test read-only scope
curl -H "Private-Token: ${GITLAB_TOKEN}" \
  "https://gitlab.kpi.tuke.sk/api/v4/projects/123/repository/commits"

# Test API scope
curl -H "Private-Token: ${GITLAB_TOKEN}" \
  "https://gitlab.kpi.tuke.sk/api/v4/projects/123/issues"

Safety recommendations

Best practices

  1. Use Group/Project tokens instead of Personal tokens
  2. Minimum permissions - only necessary scopes
  3. Short expiration - max 6 months for production
  4. Rotation - regular exchange of tokens
  5. Audit - monitor token usage

What to avoid

  1. Token sharing between environments
  2. Tokens in Git repository
  3. Personal tokens in production
  4. Tokens without expiration

Audit log

SQL
-- All API calls with the token
SELECT 
    timestamp,
    endpoint,
    method,
    response_status,
    user_agent
FROM api_audit_log
WHERE token_hash = 'sha256:xxxx'
ORDER BY timestamp DESC
LIMIT 100;

Further reading