Service Authentication

last updated: 2025-07-21

Deploying Services with DTZ Authentication

DTZ provides built-in authentication capabilities for your deployed services, making it easy to build secure applications without managing your own authentication infrastructure.

Overview

When you deploy a service to DTZ, the platform automatically provides authentication credentials and context information through environment variables. Your service can use these to:

  • Authenticate requests to other DTZ services (API calls, object storage, etc.)
  • Verify incoming user requests
  • Access context-specific resources
  • Implement secure service-to-service communication

Environment Variables

DTZ automatically injects the following environment variables into your service containers:

Variable Description Example
DTZ_ACCESS_TOKEN JWT token for accessing DTZ services within your context eyJhbGciOiJSUzI1NiI...
DTZ_CONTEXT_ID Your DTZ context identifier context-3cd84429-64a4-4226-b868-c83feeff0f46
PORT Port your service should listen on 80

Authentication Methods for Incoming Requests

Your deployed service can authenticate incoming requests using several methods:

API Key Authentication

Users can authenticate with your service using DTZ API keys:

curl -H "X-API-KEY: your-api-key" https://yourservice.dtz.rocks/api/endpoint

Bearer Token Authentication

JWT tokens can be passed via Authorization header:

curl -H "Authorization: Bearer your-jwt-token" https://yourservice.dtz.rocks/api/endpoint

Basic Authentication

API keys can also be passed via basic auth:

curl -u apikey:your-api-key https://yourservice.dtz.rocks/api/endpoint

For web applications, authentication can work through browser cookies set by DTZ Identity service.

OAuth Flow

DTZ provides automatic OAuth authentication for web applications. When unauthenticated users access your service, they are automatically redirected to the DTZ login page and redirected back after successful authentication.

Using DTZ Authentication in Your Service

Making Authenticated Requests to DTZ Services

Use the DTZ_ACCESS_TOKEN environment variable to make authenticated calls to other DTZ services:

import os
import requests

# Get the DTZ access token from environment
token = os.environ.get('DTZ_ACCESS_TOKEN')
context_id = os.environ.get('DTZ_CONTEXT_ID')

# Make authenticated request to DTZ API
headers = {
    'Authorization': f'Bearer {token}',
    'Content-Type': 'application/json'
}

response = requests.get(
    'https://api.dtz.rocks/v1/containers/services',
    headers=headers
)
// Node.js example
const token = process.env.DTZ_ACCESS_TOKEN;
const contextId = process.env.DTZ_CONTEXT_ID;

const response = await fetch('https://api.dtz.rocks/v1/containers/services', {
    headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
    }
});
# Bash example
curl -H "Authorization: Bearer $DTZ_ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     https://api.dtz.rocks/v1/containers/services

Verifying Incoming Authentication

DTZ automatically handles authentication verification for incoming requests. When a user makes an authenticated request to your service, DTZ:

  1. Validates the authentication credentials
  2. Converts API keys to JWT tokens
  3. Forwards the request with a Authorization: Bearer <token> header

Your service receives the JWT token and can extract user information:

import jwt
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/protected')
def protected_endpoint():
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return {'error': 'No authentication provided'}, 401
    
    token = auth_header.split(' ')[1]
    
    try:
        # The token is already verified by DTZ
        # You can extract claims without verification
        payload = jwt.decode(token, options={"verify_signature": False})
        
        user_id = payload.get('sub')  # Identity ID
        context_id = payload.get('scope')  # Context ID
        roles = payload.get('roles', [])  # User roles
        
        return {
            'user_id': user_id,
            'context_id': context_id,
            'roles': roles,
            'message': 'Access granted'
        }
    except jwt.InvalidTokenError:
        return {'error': 'Invalid token'}, 401
// Express.js example
const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

app.get('/protected', (req, res) => {
    const authHeader = req.headers.authorization;
    
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ error: 'No authentication provided' });
    }
    
    const token = authHeader.split(' ')[1];
    
    try {
        // Token is already verified by DTZ
        const payload = jwt.decode(token);
        
        const userId = payload.sub;      // Identity ID
        const contextId = payload.scope; // Context ID
        const roles = payload.roles || [];    // User roles
        
        res.json({
            user_id: userId,
            context_id: contextId,
            roles: roles,
            message: 'Access granted'
        });
    } catch (error) {
        res.status(401).json({ error: 'Invalid token' });
    }
});

JWT Token Structure

DTZ JWT tokens contain the following claims:

Claim Description Example
iss Issuer (always “dtz.rocks”) "dtz.rocks"
sub Subject (user identity ID) "identity-abc123..."
aud Audience (always “dtz.rocks”) "dtz.rocks"
scope Context ID "context-3cd84429..."
roles User roles/permissions ["https://dtz.rocks/context/admin/{context_id}"]
contexts Available contexts ["context-3cd84429..."]
exp Expiration time 1640995200
iat Issued at time 1640908800

Role-Based Access Control

DTZ uses role-based access control with URI-based role identifiers. Common role patterns:

  • https://dtz.rocks/context/admin/{context_id} - Context administrator
  • https://dtz.rocks/containers/admin/{context_id} - Container service administrator
  • https://dtz.rocks/objectstore/admin/{context_id} - Object store administrator

You can check roles in your service:

def check_role(token, required_role_pattern):
    payload = jwt.decode(token, options={"verify_signature": False})
    roles = payload.get('roles', [])
    context_id = payload.get('scope')
    
    required_role = required_role_pattern.replace('{context_id}', context_id)
    return required_role in roles

# Usage
if check_role(token, 'https://dtz.rocks/containers/admin/{context_id}'):
    # User has container admin permissions
    pass

Best Practices

Security

  • Always validate JWT tokens contain expected claims
  • Check user roles before granting access to sensitive operations
  • Use HTTPS for all communications
  • Don’t log sensitive authentication tokens

Error Handling

  • Return appropriate HTTP status codes (401 for unauthorized, 403 for forbidden)
  • Provide meaningful error messages without exposing sensitive information

Performance

  • Cache JWT token validation results when possible
  • Use connection pooling for DTZ API calls
  • Consider implementing request rate limiting

Example: Complete Authenticated Service

Here’s a complete example of a Python Flask service with DTZ authentication:

import os
import jwt
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

DTZ_TOKEN = os.environ.get('DTZ_ACCESS_TOKEN')
DTZ_CONTEXT_ID = os.environ.get('DTZ_CONTEXT_ID')

def get_user_from_token(token):
    """Extract user information from DTZ JWT token."""
    try:
        payload = jwt.decode(token, options={"verify_signature": False})
        return {
            'user_id': payload.get('sub'),
            'context_id': payload.get('scope'),
            'roles': payload.get('roles', [])
        }
    except jwt.InvalidTokenError:
        return None

def require_auth(f):
    """Decorator to require authentication."""
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return jsonify({'error': 'Authentication required'}), 401
        
        token = auth_header.split(' ')[1]
        user = get_user_from_token(token)
        
        if not user:
            return jsonify({'error': 'Invalid token'}), 401
        
        request.user = user
        return f(*args, **kwargs)
    
    decorated.__name__ = f.__name__
    return decorated

@app.route('/health')
def health():
    """Public health check endpoint."""
    return jsonify({'status': 'healthy'})

@app.route('/profile')
@require_auth
def profile():
    """Protected endpoint returning user profile."""
    return jsonify({
        'user_id': request.user['user_id'],
        'context_id': request.user['context_id'],
        'roles': request.user['roles']
    })

@app.route('/admin/users')
@require_auth
def admin_users():
    """Admin-only endpoint."""
    required_role = f'https://dtz.rocks/context/admin/{DTZ_CONTEXT_ID}'
    
    if required_role not in request.user['roles']:
        return jsonify({'error': 'Admin access required'}), 403
    
    # Make authenticated request to DTZ API
    headers = {'Authorization': f'Bearer {DTZ_TOKEN}'}
    response = requests.get(
        'https://identity.dtz.rocks/api/2021-02-21/users',
        headers=headers
    )
    
    return jsonify(response.json())

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 80))
    app.run(host='0.0.0.0', port=port)

Troubleshooting

Common Issues

Authentication token not found: Ensure your service is deployed through DTZ containers service and the environment variables are being read correctly.

Invalid token errors: Check that you’re correctly extracting the token from the Authorization header and that the JWT parsing is working.

403 Forbidden errors: Verify the user has the required roles in their JWT token.

Service-to-service authentication failing: Ensure you’re using the DTZ_ACCESS_TOKEN environment variable for outbound requests.

Testing Authentication

You can test your service authentication using curl:

# Test with API key
curl -H "X-API-KEY: your-api-key" https://yourservice.dtz.rocks/profile

# Test with bearer token  
curl -H "Authorization: Bearer your-jwt-token" https://yourservice.dtz.rocks/profile

# Test unauthenticated (should return 401)
curl https://yourservice.dtz.rocks/profile

For more detailed information about DTZ authentication, see the Authentication documentation.