Skip to main content

Session Management

The Multi-Cloud Manager maintains server-side sessions that store user authentication state and connected cloud provider accounts. These endpoints allow clients to check authentication status, retrieve connected accounts, and manage sessions.

Get Current User

Response

When authenticated:
logged_in
boolean
Always true when user is authenticated
name
string
User’s display name from the authentication provider
{
  "logged_in": true,
  "name": "John Doe"
}
When not authenticated:
{
  "logged_in": false
}

Implementation Details

This endpoint checks for the presence of a user object in the session. The user object is set during OAuth callbacks for Azure and GCP authentication. Code reference: backend/azure_modules/utils.py:46-50
def api_user():
    user = get_user()
    if not user: 
        return jsonify({"logged_in": False}), 200 
    return jsonify({"logged_in": True, "name": user.get("name")}), 200

Get Connected Accounts

Response

Returns an array of account objects, one for each connected cloud provider.
accounts
array
Array of connected cloud provider account objects
Azure Account Object:
provider
string
Value: "azure"
tenantId
string
Azure Active Directory tenant ID
displayName
string
User’s display name from Azure AD
subscriptions
array
Array of subscription IDs accessible by the user
GCP Account Object:
provider
string
Value: "gcp"
email
string
User’s Google email address
displayName
string
User’s display name from Google profile
access_token
string
GCP API access token
refresh_token
string
Refresh token for obtaining new access tokens
AWS Account Object:
provider
string
Value: "aws"
displayName
string
Display name in format: "AWS Account ({account_id})"
roleArn
string
IAM role ARN for cross-account access
externalId
string
External ID used in role assumption
accountId
string
AWS account ID
Example response:
[
  {
    "provider": "azure",
    "tenantId": "12345678-1234-1234-1234-123456789012",
    "displayName": "John Doe",
    "subscriptions": [
      "abcd1234-5678-90ab-cdef-1234567890ab",
      "efgh5678-90ab-cdef-1234-567890abcdef"
    ]
  },
  {
    "provider": "gcp",
    "email": "[email protected]",
    "displayName": "John Doe",
    "access_token": "ya29.a0AfH6SMBx...",
    "refresh_token": "1//0gHZx..."
  },
  {
    "provider": "aws",
    "displayName": "AWS Account (987654321098)",
    "roleArn": "arn:aws:iam::987654321098:role/MultiCloudManagerRole",
    "externalId": "multi-cloud-manager-app-v1-secret",
    "accountId": "987654321098"
  }
]
When no accounts connected:
[]

Implementation Details

Code reference: backend/azure_modules/utils.py:42-44
def api_accounts():
    accounts = session.get("accounts", []) 
    return jsonify(accounts), 200

Get Azure Subscriptions

Response

value
array
Array of Azure subscription objects with full details
Subscription Object:
provider
string
Always "azure"
tenantId
string
Azure tenant ID that owns the subscription
subscriptionId
string
Azure subscription ID (GUID)
displayName
string
Subscription display name from Azure
Example response:
{
  "value": [
    {
      "provider": "azure",
      "tenantId": "12345678-1234-1234-1234-123456789012",
      "subscriptionId": "abcd1234-5678-90ab-cdef-1234567890ab",
      "displayName": "Production Subscription"
    },
    {
      "provider": "azure",
      "tenantId": "12345678-1234-1234-1234-123456789012",
      "subscriptionId": "efgh5678-90ab-cdef-1234-567890abcdef",
      "displayName": "Development Subscription"
    }
  ]
}

Error Responses

500 Internal Server Error
{
  "error": "Error message details"
}
Returned when Azure SDK fails to list subscriptions (e.g., invalid credentials, expired tokens, permission issues).

Implementation Details

This endpoint:
  1. Iterates through all accounts in the session
  2. Filters for Azure accounts only (provider == "azure")
  3. For each Azure account, creates a SubscriptionClient using service principal credentials
  4. Lists all subscriptions using client.subscriptions.list()
  5. Returns enriched subscription details with tenant ID and provider info
Code reference: backend/azure_modules/utils.py:52-69
def api_subscriptions():
    accounts = session.get("accounts", [])
    items = []
    for acc in accounts:
        if acc.get("provider") != "azure":
            continue
        try:
            client = get_subscription_client(acc["tenantId"])
            for s in client.subscriptions.list():
                items.append({
                    "provider": "azure",
                    "tenantId": acc["tenantId"],
                    "subscriptionId": s.subscription_id,
                    "displayName": s.display_name
                })
        except Exception as e:
            return jsonify({"error": str(e)}), 500
    return jsonify({"value": items})

Logout

Response

200 OK
{
  "message": "Wylogowano"
}

Implementation Details

Clears all session data including:
  • User authentication info (session["user"])
  • Access tokens (session["access_token"])
  • Connected accounts (session["accounts"])
  • Any other session data
Code reference: backend/azure_modules/utils.py:38-40
def logout():
    session.clear()
    return jsonify({"message": "Wylogowano"}), 200
Note: After logout, the client should redirect the user to the login page or home page.

Session Storage

All session data is stored server-side using Flask sessions. The session is secured with a secret key configured in the application:
app.secret_key = "super-secret-key"
Security Note: In production, use a strong, randomly generated secret key and store it securely (environment variable or secrets manager).

Session Data Structure

session = {
    "user": {  # Set by Azure/GCP OAuth
        "name": "John Doe",
        "email": "[email protected]",
        # ... other ID token claims
    },
    "access_token": "bearer_token_here",
    "accounts": [
        # Azure, GCP, and AWS account objects
    ]
}

CORS Configuration

The API is configured with CORS to allow requests from the frontend:
CORS(app, supports_credentials=True, origins=["http://localhost:3000"])
Important: Session cookies require supports_credentials=True and the client must send requests with credentials (e.g., credentials: 'include' in fetch API).

Authentication Flow

Initial Authentication

  1. User navigates to login page
  2. User clicks “Login with Azure” or “Login with Google”
  3. OAuth flow completes (see Azure Login or GCP Login pages)
  4. User object and access token stored in session
  5. User redirected to dashboard

Checking Authentication Status

// Frontend check
fetch('/api/user', { credentials: 'include' })
  .then(res => res.json())
  .then(data => {
    if (data.logged_in) {
      console.log('User:', data.name);
    } else {
      // Redirect to login
    }
  });

Loading Connected Accounts

// Get all connected accounts
fetch('/api/accounts', { credentials: 'include' })
  .then(res => res.json())
  .then(accounts => {
    accounts.forEach(acc => {
      console.log(`Connected: ${acc.provider} - ${acc.displayName}`);
    });
  });

Logging Out

// Logout
fetch('/api/logout', { credentials: 'include' })
  .then(() => {
    window.location.href = '/';
  });

Code References

Session utilities: backend/azure_modules/utils.py:38-69 Get user helper:
def get_user():
    return session.get("user")
Route registration: backend/azure_modules/routes.py:94-97
azure_bp_module.route("/api/user")(api_user)
azure_bp_module.route("/api/subscriptions")(api_subscriptions)
azure_bp_module.route("/api/accounts")(api_accounts)
azure_bp_module.route("/api/logout")(logout)

Build docs developers (and LLMs) love