Skip to main content

idkollen_client/models/
bankid_se.rs

1use chrono::NaiveDate;
2use serde::{Deserialize, Serialize};
3
4use super::common::{ApiErrorCode, CallInitiator};
5use super::ip_address::IpAddress;
6use super::org_number::OrgNumber;
7use super::ssn::Pno;
8use super::url::Url;
9
10/// Request body for starting a BankID SE authentication session.
11#[must_use]
12#[derive(Debug, Clone, Default, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct BankIdSeAuthRequest {
15    /// Swedish personal identification number. Restricts the session to this user.
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub ssn: Option<Pno>,
18    /// End-user IP address (or the closest proxy address).
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub ip_address: Option<IpAddress>,
21    /// URL to receive the result callback on success or failure.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub callback_url: Option<Url>,
24    /// Force PIN entry even when biometrics are enabled.
25    pub pin_required: bool,
26    /// Text describing the purpose of the identification, shown to the user.
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub intent: Option<String>,
29    /// Swedish organisation number — enables company signatory check.
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub org_number: Option<OrgNumber>,
32    /// Fetch the user's registered address on completion.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub request_address: Option<bool>,
35    /// Reference ID returned verbatim in the result and callback.
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub ref_id: Option<String>,
38}
39
40impl BankIdSeAuthRequest {
41    #[inline]
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    #[inline]
47    pub fn ssn(mut self, ssn: Pno) -> Self {
48        self.ssn = Some(ssn);
49        self
50    }
51
52    #[inline]
53    pub fn ip_address(mut self, ip: IpAddress) -> Self {
54        self.ip_address = Some(ip);
55        self
56    }
57
58    #[inline]
59    pub fn callback_url(mut self, url: Url) -> Self {
60        self.callback_url = Some(url);
61        self
62    }
63
64    #[inline]
65    pub fn pin_required(mut self, required: bool) -> Self {
66        self.pin_required = required;
67        self
68    }
69
70    #[inline]
71    pub fn intent(mut self, intent: impl Into<String>) -> Self {
72        self.intent = Some(intent.into());
73        self
74    }
75
76    #[inline]
77    pub fn org_number(mut self, org_number: OrgNumber) -> Self {
78        self.org_number = Some(org_number);
79        self
80    }
81
82    #[inline]
83    pub fn request_address(mut self, request: bool) -> Self {
84        self.request_address = Some(request);
85        self
86    }
87
88    #[inline]
89    pub fn ref_id(mut self, ref_id: impl Into<String>) -> Self {
90        self.ref_id = Some(ref_id.into());
91        self
92    }
93}
94
95/// Request body for starting a BankID SE signing session.
96#[must_use]
97#[derive(Debug, Clone, Serialize)]
98#[serde(rename_all = "camelCase")]
99pub struct BankIdSeSignRequest {
100    /// Visible text the user must approve in BankID (max 50 000 chars).
101    pub text: String,
102    /// Restrict the signing session to this Swedish personal number.
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub ssn: Option<Pno>,
105    /// End-user IP address (or the closest proxy address).
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub ip_address: Option<IpAddress>,
108    /// URL to receive the result callback on success or failure.
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub callback_url: Option<Url>,
111    /// Force PIN entry even when biometrics are enabled.
112    pub pin_required: bool,
113    /// Hash digest of an associated file.
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub digest: Option<String>,
116    /// Swedish organisation number — enables company signatory check.
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub org_number: Option<OrgNumber>,
119    /// Fetch the user's registered address on completion.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub request_address: Option<bool>,
122    /// Reference ID returned verbatim in the result and callback.
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub ref_id: Option<String>,
125}
126
127impl BankIdSeSignRequest {
128    #[inline]
129    pub fn new(text: impl Into<String>) -> Self {
130        Self {
131            text: text.into(),
132            ssn: None,
133            ip_address: None,
134            callback_url: None,
135            pin_required: false,
136            digest: None,
137            org_number: None,
138            request_address: None,
139            ref_id: None,
140        }
141    }
142
143    #[inline]
144    pub fn ssn(mut self, ssn: Pno) -> Self {
145        self.ssn = Some(ssn);
146        self
147    }
148
149    #[inline]
150    pub fn ip_address(mut self, ip: IpAddress) -> Self {
151        self.ip_address = Some(ip);
152        self
153    }
154
155    #[inline]
156    pub fn callback_url(mut self, url: Url) -> Self {
157        self.callback_url = Some(url);
158        self
159    }
160
161    #[inline]
162    pub fn pin_required(mut self, required: bool) -> Self {
163        self.pin_required = required;
164        self
165    }
166
167    #[inline]
168    pub fn digest(mut self, digest: impl Into<String>) -> Self {
169        self.digest = Some(digest.into());
170        self
171    }
172
173    #[inline]
174    pub fn org_number(mut self, org_number: OrgNumber) -> Self {
175        self.org_number = Some(org_number);
176        self
177    }
178
179    #[inline]
180    pub fn request_address(mut self, request: bool) -> Self {
181        self.request_address = Some(request);
182        self
183    }
184
185    #[inline]
186    pub fn ref_id(mut self, ref_id: impl Into<String>) -> Self {
187        self.ref_id = Some(ref_id.into());
188        self
189    }
190}
191
192/// Request body for starting a BankID SE phone authentication session.
193#[must_use]
194#[derive(Debug, Clone, Serialize)]
195#[serde(rename_all = "camelCase")]
196pub struct BankIdSePhoneAuthRequest {
197    /// Swedish personal identification number of the user to authenticate.
198    pub ssn: Pno,
199    /// Whether the user or the RP initiated the phone call.
200    pub call_initiator: CallInitiator,
201    /// URL to receive the result callback on success or failure.
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub callback_url: Option<Url>,
204    /// Force PIN entry even when biometrics are enabled.
205    pub pin_required: bool,
206    /// Text describing the purpose of the identification, shown to the user.
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub intent: Option<String>,
209    /// Swedish organisation number — enables company signatory check.
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub org_number: Option<OrgNumber>,
212    /// Fetch the user's registered address on completion.
213    #[serde(skip_serializing_if = "Option::is_none")]
214    pub request_address: Option<bool>,
215    /// Reference ID returned verbatim in the result and callback.
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub ref_id: Option<String>,
218}
219
220impl BankIdSePhoneAuthRequest {
221    #[inline]
222    pub fn new(ssn: Pno, call_initiator: CallInitiator) -> Self {
223        Self {
224            ssn,
225            call_initiator,
226            callback_url: None,
227            pin_required: false,
228            intent: None,
229            org_number: None,
230            request_address: None,
231            ref_id: None,
232        }
233    }
234
235    #[inline]
236    pub fn callback_url(mut self, url: Url) -> Self {
237        self.callback_url = Some(url);
238        self
239    }
240
241    #[inline]
242    pub fn pin_required(mut self, required: bool) -> Self {
243        self.pin_required = required;
244        self
245    }
246
247    #[inline]
248    pub fn intent(mut self, intent: impl Into<String>) -> Self {
249        self.intent = Some(intent.into());
250        self
251    }
252
253    #[inline]
254    pub fn org_number(mut self, org_number: OrgNumber) -> Self {
255        self.org_number = Some(org_number);
256        self
257    }
258
259    #[inline]
260    pub fn request_address(mut self, request: bool) -> Self {
261        self.request_address = Some(request);
262        self
263    }
264
265    #[inline]
266    pub fn ref_id(mut self, ref_id: impl Into<String>) -> Self {
267        self.ref_id = Some(ref_id.into());
268        self
269    }
270}
271
272/// Request body for starting a BankID SE phone signing session.
273#[must_use]
274#[derive(Debug, Clone, Serialize)]
275#[serde(rename_all = "camelCase")]
276pub struct BankIdSePhoneSignRequest {
277    /// Swedish personal identification number of the user to sign.
278    pub ssn: Pno,
279    /// Whether the user or the RP initiated the phone call.
280    pub call_initiator: CallInitiator,
281    /// Visible text the user must approve in BankID (max 50 000 chars).
282    pub text: String,
283    /// URL to receive the result callback on success or failure.
284    #[serde(skip_serializing_if = "Option::is_none")]
285    pub callback_url: Option<Url>,
286    /// Force PIN entry even when biometrics are enabled.
287    pub pin_required: bool,
288    /// Hash digest of an associated file.
289    #[serde(skip_serializing_if = "Option::is_none")]
290    pub digest: Option<String>,
291    /// Swedish organisation number — enables company signatory check.
292    #[serde(skip_serializing_if = "Option::is_none")]
293    pub org_number: Option<OrgNumber>,
294    /// Fetch the user's registered address on completion.
295    #[serde(skip_serializing_if = "Option::is_none")]
296    pub request_address: Option<bool>,
297    /// Reference ID returned verbatim in the result and callback.
298    #[serde(skip_serializing_if = "Option::is_none")]
299    pub ref_id: Option<String>,
300}
301
302impl BankIdSePhoneSignRequest {
303    pub fn new(ssn: Pno, call_initiator: CallInitiator, text: impl Into<String>) -> Self {
304        Self {
305            ssn,
306            call_initiator,
307            text: text.into(),
308            callback_url: None,
309            pin_required: false,
310            digest: None,
311            org_number: None,
312            request_address: None,
313            ref_id: None,
314        }
315    }
316
317    pub fn callback_url(mut self, url: Url) -> Self {
318        self.callback_url = Some(url);
319        self
320    }
321
322    pub fn pin_required(mut self, required: bool) -> Self {
323        self.pin_required = required;
324        self
325    }
326
327    pub fn digest(mut self, digest: impl Into<String>) -> Self {
328        self.digest = Some(digest.into());
329        self
330    }
331
332    pub fn org_number(mut self, org_number: OrgNumber) -> Self {
333        self.org_number = Some(org_number);
334        self
335    }
336
337    pub fn request_address(mut self, request: bool) -> Self {
338        self.request_address = Some(request);
339        self
340    }
341
342    pub fn ref_id(mut self, ref_id: impl Into<String>) -> Self {
343        self.ref_id = Some(ref_id.into());
344        self
345    }
346}
347
348/// Request body for verifying a scanned BankID SE QR code.
349#[derive(Debug, Clone, Serialize)]
350#[serde(rename_all = "camelCase")]
351pub struct BankIdSeVerifyRequest {
352    /// Complete content of the scanned BankID QR code.
353    pub qr_code: String,
354}
355
356impl BankIdSeVerifyRequest {
357    pub fn new(qr_code: impl Into<String>) -> Self {
358        Self {
359            qr_code: qr_code.into(),
360        }
361    }
362}
363
364/// BankID SE session status.
365#[non_exhaustive]
366#[derive(Debug, Clone, Deserialize)]
367#[serde(tag = "status")]
368pub enum BankIdSeStatus {
369    #[serde(rename = "PENDING")]
370    Pending(BankIdSePending),
371    #[serde(rename = "COMPLETED")]
372    Completed(BankIdSeCompleted),
373    #[serde(rename = "FAILED")]
374    Failed(BankIdSeFailed),
375}
376
377/// Returned while the user has not yet acted in the BankID app.
378#[derive(Debug, Clone, Deserialize)]
379#[serde(rename_all = "camelCase")]
380pub struct BankIdSePending {
381    /// BankID order reference / session ID.
382    pub id: String,
383    /// Reference ID returned verbatim in the result and callback.
384    pub ref_id: Option<String>,
385    /// Token for launching the BankID app directly (autostart URL). Absent in phone-auth flows.
386    pub auto_start_token: Option<String>,
387    /// Static token used to seed the animated QR code. Absent in phone-auth flows.
388    pub qr_start_token: Option<String>,
389    /// Secret used together with `qr_start_token` to generate QR frames. Absent in phone-auth flows.
390    pub qr_start_secret: Option<String>,
391    /// BankID hint code describing the current waiting state.
392    pub hint_code: Option<String>,
393}
394
395/// Returned when the BankID session has completed successfully.
396#[derive(Debug, Clone, Deserialize)]
397#[serde(rename_all = "camelCase")]
398pub struct BankIdSeCompleted {
399    /// BankID order reference / session ID.
400    pub id: String,
401    /// Reference ID returned verbatim in the result and callback.
402    pub ref_id: Option<String>,
403    /// Swedish personal identification number (personnummer).
404    pub ssn: Pno,
405    pub name: String,
406    pub given_name: String,
407    pub surname: String,
408    /// Date the BankID certificate became valid (YYYY-MM-DD).
409    pub cert_start_date: Option<NaiveDate>,
410    /// Present only when `request_address` was `true`.
411    pub address: Option<String>,
412    /// Company signatory result text. Present only when `org_number` was provided.
413    pub company_signatory_text: Option<String>,
414}
415
416/// Returned when the BankID session has failed.
417#[derive(Debug, Clone, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct BankIdSeFailed {
420    /// BankID order reference / session ID.
421    pub id: String,
422    /// Reference ID returned verbatim in the result and callback.
423    pub ref_id: Option<String>,
424    pub error: ApiErrorCode,
425}
426
427/// Response from the BankID SE QR code verification endpoint.
428#[derive(Debug, Clone, Deserialize)]
429#[serde(rename_all = "camelCase")]
430pub struct BankIdSeVerifyResponse {
431    /// Swedish personal identification number.
432    pub ssn: Pno,
433    pub name: String,
434    pub given_name: String,
435    pub surname: String,
436    pub age: Option<u8>,
437    /// Date the QR code was verified (YYYY-MM-DD, UTC).
438    pub verified_at: Option<NaiveDate>,
439}