The Charm Store will undergo scheduled database maintenance on July 5, 2026 22:00 to July 6, 02:00 UTC. During this time, you may be unable to access charm and bundle metadata or publish updates. No user action is required and services will automatically resume once maintenance is complete.

Kratos

Platform:

Channel Revision Published Runs on
latest/stable 565 02 Feb 2026
Ubuntu 22.04
latest/edge 571 06 May 2026
Ubuntu 22.04
istio/edge 548 10 Mar 2025
Ubuntu 22.04
0.5/edge 565 24 Nov 2025
Ubuntu 22.04
0.4/edge 561 13 Aug 2025
Ubuntu 22.04
0.3/edge 419 05 Jul 2024
Ubuntu 22.04
0.2/stable 406 26 Jun 2024
Ubuntu 22.04
0.2/edge 406 02 May 2024
Ubuntu 22.04
0.1/edge 383 29 Sep 2023
Ubuntu 22.04
juju deploy kratos

#!/usr/bin/env python3
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.

"""This interface is deprecated in favor of kratos_info.
Interface library for sharing kratos endpoints.
This library provides a Python API for both requesting and providing public and admin endpoints.
## Getting Started
To get started using the library, you need to fetch the library using `charmcraft`.
```shell
cd some-charm
charmcraft fetch-lib charms.kratos.v0.kratos_endpoints
```
To use the library from the requirer side:
In the `metadata.yaml` of the charm, add the following:
```yaml
requires:
  kratos-endpoint-info:
    interface: kratos_endpoints
    limit: 1
```
Then, to initialise the library:
```python
from charms.kratos.v0.kratos_endpoints import (
    KratosEndpointsRelationError,
    KratosEndpointsRequirer,
)
Class SomeCharm(CharmBase):
    def __init__(self, *args):
        self.kratos_endpoints_relation = KratosEndpointsRequirer(self)
        self.framework.observe(self.on.some_event_emitted, self.some_event_function)
    def some_event_function():
        # fetch the relation info
        try:
            kratos_data = self.kratos_endpoints_relation.get_kratos_endpoints()
        except KratosEndpointsRelationError as error:
            ...
```
"""

import logging
from typing import Dict, Optional

from ops.charm import CharmBase, RelationCreatedEvent
from ops.framework import EventBase, EventSource, Object, ObjectEvents

# The unique Charmhub library identifier, never change it
LIBID = "5868b36df1c04c90b33f5e5557327162"

# Increment this major API version when introducing breaking changes
LIBAPI = 0

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 5

RELATION_NAME = "kratos-endpoint-info"
INTERFACE_NAME = "kratos_endpoints"
logger = logging.getLogger(__name__)


class KratosEndpointsRelationReadyEvent(EventBase):
    """Event to notify the charm that the relation is ready."""


class KratosEndpointsProviderEvents(ObjectEvents):
    """Event descriptor for events raised by `KratosEndpointsProvider`."""

    ready = EventSource(KratosEndpointsRelationReadyEvent)


class KratosEndpointsProvider(Object):
    """Provider side of the kratos-endpoint-info relation."""

    on = KratosEndpointsProviderEvents()

    def __init__(self, charm: CharmBase, relation_name: str = RELATION_NAME):
        super().__init__(charm, relation_name)

        self._charm = charm
        self._relation_name = relation_name

        events = self._charm.on[relation_name]
        self.framework.observe(
            events.relation_created, self._on_provider_endpoint_relation_created
        )

    def _on_provider_endpoint_relation_created(self, event: RelationCreatedEvent) -> None:
        self.on.ready.emit()

    def send_endpoint_relation_data(self, admin_endpoint: str, public_endpoint: str) -> None:
        """Updates relation with endpoints info."""
        if not self._charm.unit.is_leader():
            return

        relations = self.model.relations[self._relation_name]
        endpoints_databag = {
            "admin_endpoint": admin_endpoint,
            "public_endpoint": public_endpoint,
            "login_browser_endpoint": f"{public_endpoint}/self-service/login/browser",
            "sessions_endpoint": f"{public_endpoint}/sessions/whoami",
        }
        for relation in relations:
            relation.data[self._charm.app].update(endpoints_databag)


class KratosEndpointsRelationError(Exception):
    """Base class for the relation exceptions."""

    pass


class KratosEndpointsRelationMissingError(KratosEndpointsRelationError):
    """Raised when the relation is missing."""

    def __init__(self) -> None:
        self.message = "Missing kratos-endpoint-info relation with kratos"
        super().__init__(self.message)


class KratosEndpointsRelationDataMissingError(KratosEndpointsRelationError):
    """Raised when information is missing from the relation."""

    def __init__(self, message: str) -> None:
        self.message = message
        super().__init__(self.message)


class KratosEndpointsRequirer(Object):
    """Requirer side of the kratos-endpoint-info relation."""

    def __init__(self, charm: CharmBase, relation_name: str = RELATION_NAME):
        super().__init__(charm, relation_name)
        self.charm = charm
        self.relation_name = relation_name

    def get_kratos_endpoints(self) -> Optional[Dict]:
        """Get the kratos endpoints."""
        endpoints = self.model.relations[self.relation_name]
        if len(endpoints) == 0:
            raise KratosEndpointsRelationMissingError()

        if not (app := endpoints[0].app):
            raise KratosEndpointsRelationMissingError()

        data = endpoints[0].data[app]

        if not data:
            logger.info("No relation data available.")
            raise KratosEndpointsRelationDataMissingError("Missing relation data")

        if "public_endpoint" not in data:
            raise KratosEndpointsRelationDataMissingError(
                "Missing public endpoint in kratos-endpoint-info relation data"
            )

        return data