Blog · Architecture

BundID in citizen-facing applications

Integrating a public-administration application with BundID — the German federal citizen account — runs through a clearly defined path: it begins at the authority, continues in the Self-Service Portal and ends in a SAML 2.0 federation. This article walks step by step through that path — from the authority identifier through certificate generation and metadata upload to a concrete Spring Security SAML2 configuration — and presents the assurance levels, the full attribute OID model and the FIT-Connect-based postbox delivery as they actually look today.

Context — what BundID is and who operates it

BundID is the German federal citizen account for natural persons. It is owned by the Federal Ministry for Digital and State Modernisation (BMDS, successor to BMI) and operated technically by ITZ-Bund. The onboarding and management interface for service providers is the Self-Service Portal at https://ssp.id.bund.de/, which has been in operation since 16 September 2024 and replaces the previous form-based application process.

Three distinctions matter to place it correctly. First: BundID is for natural persons — companies identify themselves via Mein Unternehmenskonto (MUK), which sits on the ELSTER tax-portal infrastructure. An application that takes filings from citizens and from self-employed persons or companies needs to integrate both accounts in parallel. Second: BundID is not an internal single sign-on for staff — it is an external identification source for citizens against public-administration services. Third: the German states have historically operated their own citizen accounts — the Bayern-ID on the AKDB platform is the most prominent example. The OZG consolidation is moving toward BundID as the nationwide standard account, but full migration of all states is not finished in 2026.

The integration path is clearly standardised since the SSP relaunch. There are three environments: an integration environment at https://int.id.bund.de/ (for tests and first-time integration, without real personal data), a test environment at https://test.id.bund.de/ (for certain test scenarios) and the production environment at https://id.bund.de/. Support runs primarily through the SSP contact form (Service → Service request); the emergency address is bundID@bmi.bund.de.

Assurance levels and identification means

BundID supports four authentication tiers. They are reported in the SAML response as the attribute stork-vt (OID urn:oid:1.2.40.0.10.2.1.1.261.94) with values STORK-QAA-Level-1 through STORK-QAA-Level-4. In the authentication request the application requests a minimum tier via RequestedAuthnContext with Comparison="minimum".

Basic registration

Username and password. Explicitly does not meet the eIDAS requirements — offered for user convenience, for example to manage one's own account and read the postbox. Suitable for non-binding interactions.

Substantial

ELSTER certificate and selected notified EU identity means. Identity is administratively verified. Sufficient for most filings without a written-form requirement.

High

"Online ID" — the German national ID card with eID function, the Smart-eID, the electronic residence permit and the EU citizen card — plus selected notified EU identity means. Mandatory wherever written form is replaced by electronic means (§ 3a VwVfG). Note: "high" is not available in all EU member states.

Identification methods

The methods selectable in the authentication request via AKDB extensions are Benutzername, eID, eIDAS, Authega, Diia, Elster and FINK. The application chooses which methods are allowed for its use.

The achieved tier sits in the attribute statement of the assertion. The central rule for the application: never trust blindly, but at every protected step check whether the session meets the required tier. To step a user up from "substantial" to "high", the application builds a new AuthnRequest with a higher RequestedAuthnContext — this is the step-up case.

Protocol choice — SAML 2.0 as the default path

Unlike many modern identity providers, BundID today works primarily with SAML 2.0. An OIDC variant is being prepared in the onboarding portal and rolled out gradually, but the overwhelming majority of production integrations — citizen-facing applications in municipalities, university portals, state agencies — use SAML. The sections below therefore focus on SAML; the configuration patterns transfer to OIDC, and the onboarding process is identical.

The SAML configuration is clearly defined. The identity provider is reached at the following URLs:

# Integration (test)
IdP metadata:      https://int.id.bund.de/idp
SSO HTTP-POST:     https://int.id.bund.de/idp/profile/SAML2/POST/SSO/
SSO HTTP-Redirect: https://int.id.bund.de/idp/profile/SAML2/Redirect/SSO/

# Production
IdP metadata:      https://id.bund.de/idp
SSO HTTP-POST:     https://id.bund.de/idp/profile/SAML2/POST/SSO/
SSO HTTP-Redirect: https://id.bund.de/idp/profile/SAML2/Redirect/SSO/

The NameIDFormat is urn:oasis:names:tc:SAML:2.0:nameid-format:transient — a deliberately short-lived identifier, not the stable subject identifier. The persistent key is instead delivered as the extident attribute with OID urn:oid:1.3.6.1.4.1.25484.494450.3 — the service-provider-specific bPK2 identifier, stable across sessions and unique per service provider.

Important — and where the OAuth analogy ends: a SAML federation has no client ID and no client secret in the OAuth sense. The service provider's identity is established by an EntityID (a URL such as https://application.example.de/saml) and an X.509 certificate uploaded to the SSP during onboarding. Message authentication uses XML signatures with RSA keys, not a shared-secret string. What is called the client secret in OAuth is here the private key for the registered certificate.

Onboarding step by step

What does a municipality or agency concretely have to do so its IT service provider can put an application live on BundID? Eight steps, in the order they occur.

Step 1 — make sure the authority has a BMI ID

The authority has to be registered in the SSP under a BMI ID — a unique identifier assigned by BMDS per authority. Without it, no integration can be requested. Many municipalities already have it because they are registered in the federal ecosystem through other OZG procedures; if in doubt, ask via the SSP contact form or by email at bundID@bmi.bund.de. This step belongs to the authority, not the IT service provider — it presupposes an administrative act on the authority's side.

Step 2 — create an SSP account

An authorised representative of the authority registers at https://ssp.id.bund.de/. From there, all integration tasks are managed — request of the authentication component, request of the postbox component, metadata upload, certificate revocation, LeiKa-service curation. The IT service provider can collaborate by delegation, but the formal request remains with the authority.

Step 3 — file the "Authentication Component" request

In the SSP menu Services → Request authentication component, the procedure is filed. Mandatory inputs include: name and description of the application, privacy notice, imprint, the list of requested attributes with a functional justification (data-minimisation principle under the GDPR), the required assurance levels, the enabled identification means and a logo in the prescribed formats. The logo, in our experience, is the most frequent cause of delay — resolution, colour space and background are strictly prescribed. Sloppiness here costs two to three working days easily.

Step 4 — generate a key pair and certificates

The application needs at least two certificates: a signing certificate (for signing AuthnRequests and SP metadata) and an encryption certificate (for decrypting the assertion returned by the IdP). Most setups cover both with the same key; in production you can register a primary and a secondary signing certificate in parallel to enable rotation without downtime.

Requirements: key algorithm RSA, signature algorithm SHA512withRSA, key length 2048 or 4096 bits. Certificates are entered into the SSP as Base64-encoded content without the BEGIN/END headers — a small but recurring pitfall. An authority with its own PKI generates the keys there; alternatively the IT service provider generates them and registers them in the SSP.

Step 5 — generate SP metadata and upload them to the SSP

The application generates its service-provider metadata as an XML document. Spring Security SAML2 publishes this file automatically at /saml2/service-provider-metadata/{registrationId}. Contents: EntityID (a URL of the application, e.g. https://application.example.de/saml), AssertionConsumerService URL (the endpoint where the assertion comes back, HTTP-POST binding), the X.509 certificates Base64-encoded, the signature method rsa-sha256 or rsa-sha512 and the encryption method aes128-cbc or aes256-gcm.

In the SSP under Services → Upload and update metadata, the values are entered into a form and the certificate is pasted in. Upload is possible at any time; processing happens, per the operator's notice, once a week, every Tuesday afternoon. That is where an integration plan has to dock with the federal cadence — if you upload on Thursday, you wait five working days.

Step 6 — wire up the IdP metadata in the application

The other direction: the application needs BundID's metadata to verify assertions and encrypt the AuthnRequest. They are fetched from https://int.id.bund.de/idp (test) or https://id.bund.de/idp (production) as XML. Spring Security can bind that file directly via metadata-uri. With platforms that only accept PEM format (HISinOne is one example), you have to extract the certificate from between the <ds:X509Certificate> tags in the metadata XML, reformat it with BEGIN/END headers (e.g. via samltool.com/format_x509cert.php) and save it as a .crt file.

Step 7 — configure the AuthnRequest with AKDB extensions

Since August 2024 BundID requires every AuthnRequest to carry the AKDB SAML extensions with namespace https://www.akdb.de/request/2018/09. They control which identification means are shown on the login screen, which use case (login, self-registration, account linking) is taken and which attributes are requested. The next section shows the XML structure concretely.

Step 8 — test the integration, then go live

First tests run against the integration environment at int.id.bund.de with synthetic test identities — username/password accounts can be self-registered, and for the eID variant you can obtain a test ID card from the BMI or simulate it with PersoSim (BSI test infrastructure, AusweisApp in developer mode). Only after all use cases have been validated — login, step-up, account linking where applicable — is the production cutover requested in the SSP.

SP metadata — the heart of the federation

The service-provider metadata are the only thing BundID formally knows about the application. A concise, correctly structured file looks like this at its core:

<md:EntityDescriptor entityID="https://application.example.de/saml"
                     xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
                     xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
                      AuthnRequestsSigned="true"
                      WantAssertionsSigned="true">

    <md:KeyDescriptor use="signing">
      <ds:KeyInfo><ds:X509Data><ds:X509Certificate>
        MIIDGDCC...   <!-- Base64, without BEGIN/END headers -->
      </ds:X509Certificate></ds:X509Data></ds:KeyInfo>
    </md:KeyDescriptor>

    <md:KeyDescriptor use="encryption">
      <ds:KeyInfo><ds:X509Data><ds:X509Certificate>
        MIIDGDCC...
      </ds:X509Certificate></ds:X509Data></ds:KeyInfo>
    </md:KeyDescriptor>

    <md:AssertionConsumerService
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
        Location="https://application.example.de/login/saml2/sso/bundid"
        index="0" isDefault="true" />
  </md:SPSSODescriptor>
</md:EntityDescriptor>

Three places are critical. The EntityID is a technical URL, not a frontend link — it must be unique, stable and entered into the SSP exactly as it appears in the XML. The AssertionConsumerService location is the HTTP-POST endpoint where the application receives the assertion; with Spring Security it defaults to /login/saml2/sso/{registrationId}. And the certificates are Base64 without headers — leaving the BEGIN/END block in the XML triggers a parser error in the SSP.

AuthnRequest with AKDB extensions

Since August 2024 BundID requires every authentication request to carry the AKDB extensions — they steer which identification means are offered and which attributes are requested. Without them, the IdP no longer accepts the request.

<samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    xmlns:akdb="https://www.akdb.de/request/2018/09"
    Destination="https://int.id.bund.de/idp/profile/SAML2/POST/SSO/"
    ID="_abc123" Version="2.0" IssueInstant="2026-05-14T10:00:00Z"
    AssertionConsumerServiceURL="https://application.example.de/login/saml2/sso/bundid"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">

  <saml:Issuer>https://application.example.de/saml</saml:Issuer>

  <samlp:Extensions>
    <akdb:AuthenticationRequest
        xmlns:akdb="https://www.akdb.de/request/2018/09" Version="2">
      <akdb:AuthnMethods>
        <akdb:Benutzername><akdb:Enabled>true</akdb:Enabled></akdb:Benutzername>
        <akdb:eID><akdb:Enabled>true</akdb:Enabled></akdb:eID>
        <akdb:eIDAS><akdb:Enabled>true</akdb:Enabled></akdb:eIDAS>
        <akdb:Elster><akdb:Enabled>true</akdb:Enabled></akdb:Elster>
      </akdb:AuthnMethods>
      <akdb:RequestedAttributes>
        <akdb:RequestedAttribute Name="urn:oid:1.3.6.1.4.1.25484.494450.3"
                                  RequiredAttribute="true" />
        <akdb:RequestedAttribute Name="urn:oid:2.5.4.42"
                                  RequiredAttribute="true" /> <!-- givenName -->
        <akdb:RequestedAttribute Name="urn:oid:2.5.4.4"
                                  RequiredAttribute="true" /> <!-- surname -->
        <akdb:RequestedAttribute Name="urn:oid:1.2.40.0.10.2.1.1.261.94"
                                  RequiredAttribute="true" /> <!-- stork-vt -->
      </akdb:RequestedAttributes>
    </akdb:AuthenticationRequest>
  </samlp:Extensions>

  <samlp:RequestedAuthnContext Comparison="minimum">
    <saml:AuthnContextClassRef>STORK-QAA-Level-3</saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

Three use cases drive the extensions: login (regular sign-in), self-registration (the citizen has no BundID account yet and creates one during sign-in) and account linking (re-binding after a pseudonym change, e.g. after replacing the national ID card). Which case is run sits in the Service element of the extensions. The exact values and code-block templates are documented in the SSP guidance at https://ssp.id.bund.de/ip?id=downloads.

Attributes and their OIDs

BundID delivers personal attributes as SAML attributes with OIDs as names — not clear-text labels as in OIDC. Which attributes arrive depends on the requested assurance level and the chosen identification means. At "basic registration" only the pseudonym arrives; at "substantial" and "high" the verified personal data are present.

givenName        urn:oid:2.5.4.42                       First name
surname          urn:oid:2.5.4.4                        Last name
email            urn:oid:0.9.2342.19200300.100.1.3      Email address
street           urn:oid:2.5.4.18                       Street address
postcode         urn:oid:2.5.4.17                       Postal code
city             urn:oid:2.5.4.7                        City
country          urn:oid:1.2.40.0.10.2.1.1.225599       Country
title            urn:oid:0.9.2342.19200300.100.1.40     Academic title
gender           urn:oid:1.3.6.1.4.1.33592.1.5.5        Gender
birthdate        urn:oid:1.2.40.0.10.2.1.1.55           Date of birth
placeOfBirth     urn:oid:1.3.6.1.5.5.7.9.2              Place of birth
birthName        urn:oid:1.2.40.0.10.2.1.1.225566       Birth name
nationality      urn:oid:1.2.40.0.10.2.1.1.225577       Nationality
phone            urn:oid:2.5.4.20                       Phone number
extident         urn:oid:1.3.6.1.4.1.25484.494450.3     bPK2 — the stable identifier
postkorb-handle  urn:oid:2.5.4.18                       Postbox identifier
stork-vt         urn:oid:1.2.40.0.10.2.1.1.261.94       Assurance level

The key attribute is extident — the service-provider-specific identifier version 2 (bPK2). It is service-provider-specific (each application receives a different identifier for the same citizen), stable across sessions, and the correct primary key in the local user table. Cross-linking the case files of two authorities via the bPK2 is technically impossible because each service provider derives its own identifier — this is the unlinkability guard under BSI TR-03130.

With eID authentication the bPK2 is bound cryptographically to the card, not to the person. Replacing the card after a loss produces a new bPK2 — the application needs an account re-binding flow for that case, typically through a case number plus date of birth.

Integration in Spring Boot with Spring Security SAML2

Spring Security 6 ships spring-boot-starter-saml2-service-provider, a production-ready SP implementation. Configuration has two parts: the application.yml with the federation registration and a SecurityFilterChain bean with attribute mapping.

Dependencies and application.yml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-saml2-service-provider</artifactId>
</dependency>
spring:
  security:
    saml2:
      relyingparty:
        registration:
          bundid:
            entity-id: https://application.example.de/saml
            assertingparty:
              # Test against integration:
              metadata-uri: https://int.id.bund.de/idp
              # For production: https://id.bund.de/idp
            signing.credentials:
              - private-key-location: classpath:saml/sp-signing.key
                certificate-location: classpath:saml/sp-signing.crt
            decryption.credentials:
              - private-key-location: classpath:saml/sp-encryption.key
                certificate-location: classpath:saml/sp-encryption.crt
server:
  forward-headers-strategy: framework

Spring publishes the SP metadata automatically at /saml2/service-provider-metadata/bundid — that is the URL referenced as the EntityID endpoint in the SSP. The last line, forward-headers-strategy, is mandatory behind a reverse proxy — otherwise Spring builds the AssertionConsumerService URL from the local view rather than the public host, and the IdP rejects with "Recipient mismatch".

SecurityFilterChain and attribute mapping

@Configuration
@EnableWebSecurity
public class BundIdSecurityConfig {

  @Bean
  SecurityFilterChain filter(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(a -> a
        .requestMatchers("/", "/public/**").permitAll()
        .requestMatchers("/filing/written-form/**").hasAuthority("LOA_HIGH")
        .requestMatchers("/filing/**").hasAnyAuthority("LOA_HIGH", "LOA_SUBSTANTIAL")
        .anyRequest().authenticated())
      .saml2Login(saml -> saml
        .authenticationManager(authMgr())
        .authenticationRequestResolver(akdbExtensionResolver()))
      .saml2Logout(Customizer.withDefaults());
    return http.build();
  }

  private AuthenticationManager authMgr() {
    OpenSaml4AuthenticationProvider p = new OpenSaml4AuthenticationProvider();
    p.setResponseAuthenticationConverter(this::convertAssertion);
    return new ProviderManager(p);
  }

  private Saml2Authentication convertAssertion(ResponseToken token) {
    Saml2Authentication base =
        OpenSaml4AuthenticationProvider
            .createDefaultResponseAuthenticationConverter().convert(token);
    Map<String, List<Object>> attrs =
        ((Saml2AuthenticatedPrincipal) base.getPrincipal()).getAttributes();

    String storkVt = firstString(attrs, "urn:oid:1.2.40.0.10.2.1.1.261.94");
    String bpk2    = firstString(attrs, "urn:oid:1.3.6.1.4.1.25484.494450.3");

    Set<GrantedAuthority> auths = new HashSet<>(base.getAuthorities());
    auths.add(mapLoa(storkVt));

    DefaultSaml2AuthenticatedPrincipal principal =
        new DefaultSaml2AuthenticatedPrincipal(bpk2, attrs);
    return new Saml2Authentication(principal,
        base.getSaml2Response(), auths);
  }

  private GrantedAuthority mapLoa(String storkVt) {
    return switch (storkVt) {
      case "STORK-QAA-Level-4" -> new SimpleGrantedAuthority("LOA_HIGH");
      case "STORK-QAA-Level-3" -> new SimpleGrantedAuthority("LOA_SUBSTANTIAL");
      default                  -> new SimpleGrantedAuthority("LOA_LOW");
    };
  }
}

The important point in the converter: the Spring principal name is set to the bPK2, not the transient NameID. That makes the stable service-provider-specific identifier the primary key for the local user table — email, name and address are only snapshot data that can change.

Build the akdbExtensionResolver() by extending the default Saml2AuthenticationRequestResolver and injecting the AKDB extensions into the Extensions element before marshalling. Spring Security provides the customiser hook in the OpenSAML4 request builder; concrete examples are available in open-source adapters such as ba-itsys/keycloak-extension-bundid (a Keycloak plugin whose logic transfers structurally to Spring).

Testing the integration — before production cutover

In the integration environment the following routes to test identities are well established.

Self-registration with username and password. The fastest way to check the end-to-end flow at "basic registration". Create an account at int.id.bund.de, confirm by email, trigger sign-in from the application — success when the bPK2 lands in the backend.

Test ID cards from the BMI. For tests at assurance level "high", the BMI hands out physical test ID cards with online function on request. These cards are cryptographically real but carry fictional personal data and are valid only in the integration environment. Request via the SSP contact form, lead time about a week.

PersoSim and AusweisApp in developer mode. BSI publishes at https://www.bsi.bund.de/DE/Themen/Oeffentliche-Verwaltung/Elektronische-Identitaeten/Online-Ausweisfunktion/Testinfrastruktur/PersoSim/PersoSim_node.html a simulator that fully emulates the national ID card chip in software. Together with AusweisApp in developer mode it lets you create arbitrary test identities — useful for load and edge-case testing.

BundID Simulator. The German Federal Employment Agency publishes at github.com/ba-itsys/bundid-simulator a functional mock that accepts SAML requests and returns responses per the BundID specification. Spring Boot application with Docker image (ghcr.io/ba-itsys/bundid-simulator), built-in list of twelve test personas, configurable responses OK / CANCEL / ERROR. Very useful in CI pipelines where the integration environment is not reachable.

Postbox and decision delivery over FIT-Connect

BundID carries an electronic postbox for every user. Decisions, however, are not delivered by the application directly — delivery runs through FIT-Connect, FITKO's connection service. Parallel to the authentication component, the postbox component is requested in the SSP and the BundID postbox certificate is issued and managed there.

FIT-Connect consists of a submission API to which the application as a sender hands over its decisions, and a delivery service that routes the submission to the recipient's delivery endpoint. For BundID citizens this is the delivery endpoint of the postbox surfaced in the id.bund.de frontend. Decisions are transported end-to-end encrypted across the FIT-Connect infrastructure — the content is encrypted as a JWE against the recipient delivery endpoint's public key and signed as a JWS with the sender's key.

FITKO publishes a Java client library that encapsulates JWE/JWS and the submission API ergonomically. Delivery status — handed over, delivered, read — comes back asynchronously by polling or webhook. For the delivery fiction (a decision is deemed delivered three days after being made available in the postbox, by analogy to § 41 VwVfG), the application has to persist the placement time in a tamper-evident manner — the appeals deadline is derived from it.

Pitfalls from production integrations

Sorted by frequency — items that show up in almost every first-time integration attempt.

Certificate format in the SSP. The certificate fields in the SSP expect only the Base64 content without -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----. Pasting the full PEM block produces a validation error and one wasted working day.

Metadata processing on a weekly cadence. Uploaded metadata are, per the reported practice, processed on Tuesday afternoons by the federal-side process. A Wednesday update is therefore only usable for authentication on the following Wednesday. Sync your integration plan with the upload window.

Re-formatting the IdP certificate. Where you integrate on a platform that does not accept the metadata XML directly (HISinOne is a prominent example), extract the certificate from between the <ds:X509Certificate> tags, paste it into a new file with BEGIN/END headers and save it as .crt. A practical helper is samltool.com/format_x509cert.php, which adds the headers for you.

Forward headers behind the reverse proxy. Spring builds the AssertionConsumerService URL from the locally visible request URL — so http://localhost:8080/... when the reverse proxy is not recognised. The IdP then rejects with "Recipient mismatch". Fix: set server.forward-headers-strategy=framework and ensure X-Forwarded-Proto and X-Forwarded-Host reach the application.

Forgetting the AKDB extensions. Mandatory since August 2024. With a default Spring Security SAML resolver that injects no extensions, the integration environment shows empty login screens or a generic error. Extend the resolver and set the akdb:AuthenticationRequest structure explicitly.

NameID model misunderstood. The transient NameID is short-lived and freshly minted per session. Using it as a user key builds a bug visible on the second sign-in. Pull the stable key from extident (bPK2).

Confusion with MUK. Filings by self-employed people or sole proprietors sometimes get routed to BundID even though they act in a business capacity and should identify via Mein Unternehmenskonto. An early question in the form and automatic routing avoid the later migration.

Outlook — BundID alongside the EUDI Wallet

In 2026/2027 the EUDI Wallet introduces a second identification means that functionally competes with BundID. The plausible architecture has BundID become a verifier against the EUDI Wallet — the citizen signs in at id.bund.de, BundID accepts both today's means (username, ELSTER, eID) and a new "sign in with EUDI Wallet"; the wallet delivers the PID credential, BundID verifies it and surfaces the familiar attributes to the applications.

For an application the right investment today is a clean SAML integration with BundID with step-up capability, bPK2-based user flow and FIT-Connect delivery. A parallel OID4VP integration directly against the wallet is a later extension that pays off for cross-border use cases or banking/insurance integrations. For purely German administrative applications, BundID will remain the primary entry point for the foreseeable future.

BundID integration or OZG modernisation?

We integrate citizen-facing applications with BundID, Mein Unternehmenskonto and the German states' citizen accounts, take care of SSP onboarding including key generation and metadata upload, wire up FIT-Connect for decision delivery and advise on the assurance-level model including step-up. The result: a clear integration plan and an architecture that carries step-up, the postbox and the later EUDI path cleanly.

Arrange a conversation