# Technical Direction

{% hint style="info" %}
This document sets a high-level technical direction for Digital Iceland. It describes architectural patterns, development tools, workflows and values that should be adopted by teams building solutions for Ísland.is.
{% endhint %}

{% hint style="info" %}
As time goes by, this document will be updated to match evolving trends in Digital Iceland as well as the global developer community.
{% endhint %}

Digital Iceland is responsible for software solutions that relate to the Icelandic [central service portal](https://stafraent.island.is/verkefni/nytt-island-is/) under the brand Ísland.is. These solutions allow companies and individuals to access government services in a simple and efficient way. Meanwhile, government organisations are responsible for their content, data and service, some of which may end up on Ísland.is.

Solutions are developed by teams, from multiple vendors and organisations, in a single [code repository](/technical-overview/monorepo). The code is open source, facilitating code reuse and allowing various parties to contribute to development and maintenance in the future.

On top of this, we enforce strict responsibilities, code reviews and automated testing to maintain good code quality.

### Architecture

There are a few software architectural patterns that Digital Iceland embraces when designing its solutions.

#### Frontend applications

Teams should implement solutions as standalone frontend applications, e.g. single-page applications (SPA) or mobile applications, and integrate them with backend services through API interfaces.

Having a clear separation between frontend and backend allows us to implement User Interfaces (UI) that behave like applications with richer and faster User Experience (UX). It also reduces coupling and scales up development, creating reusable backend services that support more varied presentation through different frontend applications.

#### Shared code

A big focus in the technical direction for Ísland.is is to support the development of code that teams can share and reuse in later projects to accelerate overall development. With time, teams get faster at implementing projects, since a lot of the individual pieces already exist. Additionally, the overall quality increases, since improvements to the shared code elevates all projects that use it.

Code can be reused at all levels, e.g.:

* UI Components like buttons, typography and forms.
* Localisation utilities to support translations in multiple languages, date and number formatting, with specialised Icelandic support.
* Authentication and authorisation logic that implements security best practices.
* Operation monitoring with logging, metrics and tracing.
* Microservices for handling PDF generation, electronic signatures, notifications, payments, audit and more.
* Client code for external services.
* Build and deployment pipelines.

#### Modular solutions

Instead of ending up with dozens, or even hundreds of solutions, Ísland.is wants to create a few monolithic, modular solutions which our teams can extend with new functionality. Examples of this include:

* One information portal for any form of content that the government wants to publish.
* One service portal, for individuals and companies to sign in and access self-service modules.
* One admin interface, for government organisations, to serve their users.
* One access control system, to authenticate users, authorize actions and delegate access.
* One API gateway to all of our microservices.

We design these solutions to give our users a consistent, high-quality UX while giving our teams the flexibility and power they need to implement their projects.

#### Microservices

For specific data or business logic which is owned by Ísland.is (as opposed to other government organisation), teams should implement them in microservices.

These microservices can store data in a database, and communicate with other services through REST communications. Teams should consider using a message bus to reduce coupling between microservices when appropriate.

Frontend applications can access these microservices through an API gateway.

### Workflow

[Interdisciplinary teams](https://stafraent.island.is/samvinna/thverfagleg-stafraen-teymi/) should perform their work using an agile methodology, like Scrum, to optimize efficiency and efficacy while embracing change and minimizing risk. Agile software development emphasizes continuous delivery, where solutions are released early and improved with time.

With continuous delivery, code changes are verified as follows to minimize the likelihood of errors:

* Teams write code in a strongly typed programming language, like TypeScript, where the compiler catches many cases of invalid code.
* The teams maintain automated tests, with a particular focus on E2E tests (e.g. interface tests) that test the solution from start to finish.
* For every change, the team and other affected parties perform a code review to verify the quality of the code.
* Last but not least, teams deploy their changes to a testing environment, where project owners, testers and designers can review and approve the implementation before it goes into production.

#### Code storage

For the development of centralized, open-source solutions, it is essential to have a shared place to store and collaborate on code.

We will use [GitHub](https://github.com/) for all development and teams must submit all code there. GitHub is the primary code hosting provider for open-sourced software development, owned by Microsoft, with an excellent feature-set and interface for code reviews and collaboration. GitHub is also integrated into many essential tools in the software development ecosystem.

Digital Iceland has set up a monorepo, which contains the code for all of its solutions in one code repository with collaboration between all teams. There are many reasons we develop in a monorepo:

* Reduce barriers for code reuse on all levels of the implementation.
* Increase cooperation and consistency in implementation between projects.
* Prevent solutions from being left and forgotten, with code rot and old dependencies.
* Support organisation-wide improvements in developer experience, hosting, performance, accessibility, design and usability.

#### Cloud hosting

We host our solutions in a containerised cloud environment, using [Docker](https://www.docker.com/resources/what-container) and [Kubernetes](https://kubernetes.io/), on AWS infrastructure. To avoid lock-in, we use open-source databases and tools that we can host on any cloud infrastructure.

With Docker containers, services run independently of the hardware. They are easy to spin up, especially suitable for Agile development with continuous delivery and can handle increased load and hardware problems.

We've configured our cloud environment with a secure virtual private network that limits external access to sensitive services as well as allowing us to set up VPN connections and fixed IP addresses to integrate with external services. We also have an [X-Road](https://x-road.global/) Security Server to access other government organisations through [Straumurinn](https://stafraent.island.is/verkefni/straumurinn/).

### Development tools

Digital Iceland chooses the primary programming languages, frameworks, tools and databases that teams should use, to increase consistency and code reuse while avoiding vendor lock-in. The primary prerequisites behind a technology choice are:

* Open-source: To minimise operational costs and reduce gatekeeping when it comes to tenders.
* Popular: To increase the talent pool among Icelandic vendors and continued support in the overall community.
* Flexible: To support reuse with more use cases and limit the total number of tools in use.
* Dependable: To support rapid software development with as few errors as possible.

#### Frontend

Our teams implement frontend applications using the [TypeScript](https://www.typescriptlang.org/) programming language. TypeScript is a popular programming language which is compiled into JavaScript and offers strict data types, readable code and a compiler that catches many errors. Deep integration in development tools helps teams build and maintain large solutions.

When creating interfaces, teams should use the [React](https://reactjs.org/) frontend framework. With React, teams create user interface (UI) components which they then arrange to form complete interfaces.

Many of these UI components can be reused for multiple interfaces, across teams and projects, e.g. buttons, inputs and navigation. Teams should add these to [Storybook](https://storybook.js.org/), which provides an overview of all reusable components, as well as a testing environment for interested stakeholders.

For interactive frontend applications, teams should use [Playwright](https://playwright.dev/) to perform automated interface tests in a browser. These tests run as part of the release workflow and verify that the application functions as expected. Teams should use [Jest](https://jestjs.io/) to implement unit and integration tests.

#### Backend

The backend is also implemented in **TypeScript**, using the [Node.JS](https://nodejs.org/en/about/) framework. By using the same programming language in the frontend and backend, we can share code, e.g. types and validation. The work becomes more efficient, with fewer developer roles since more developers can work on both sides. Node.JS also has a large and active open-source community, with mature code libraries covering most needs.

Backend servers should provide a [GraphQL](https://graphql.org/) interface for frontend clients. It defines a schema that describes all the available data and operations. Whenever possible, the schema should represent an idealised world independent of implementation details. When designed well, it is possible to replace backend systems without changing the schema or frontend.

GraphQL provides better separation between the frontend and backend. In one GraphQL query, the frontend can ask for everything it requires. The GraphQL server calls web services and databases as needed to resolve the query, and the result contains only the data that the frontend requested.

If the backend contains a lot of complexity or stores data in a database, teams should consider implementing it as a special REST microservice that the GraphQL server wraps.

## Values

With centralized development and strict values, we can improve our service level, make development teams more efficient and save money with centralized experience and implementations.

These values apply to all of Digital Iceland's development under the Ísland.is brand.

### Accessibility

All websites and digital government services need to be accessible to all users. Teams should be knowledgeable about accessibility standards like the Web Content Accessibility Guidelines (WCAG) and should aim for Level AAA of WCAG version 2.1 when working on Ísland.is solutions.

All solutions built for Ísland.is will be audited according to the [Commission Implementing Decision (EU) 2018/1524](https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32018D1524\&from=EN) (Accessibility of websites). The decision includes requirements to periodically test user interfaces with automatic accessibility tests and manual audits for critical interfaces. Additionally, it emphasizes an efficient reporting system where users can report accessibility issues which we address quickly and securely.

You can find more information about the government's website accessibility policy from [the Government of Iceland](https://www.stjornarradid.is/um-vefinn/adgengisstefna/).

Teams should test web interfaces and ensure they work on different devices and in all browsers with more than 1% usage in Iceland, according to StatCounter.

### Developer Environment

With centralized solutions, we need to create and maintain a development environment that facilitates rapid development with multiple teams.

Coding standards, automatic formatting and linting tools help developers write similar code. Automated tests give us confidence that existing business logic works as intended. Feature deployments give designers, testers and other stakeholders access to verify that a change is good and working correctly.

The development environment should help new projects, and new developers get started, with clear documentation, setup guides and development servers (e.g. with [Docker](https://www.docker.com/resources/what-container)). It's essential to grant developers access to test services and data, but also a secure authorization system and workflows when it comes to more sensitive secrets and data.

### Free and Open-Source Software (FOSS)

Digital Iceland dedicates to develop new software in a free and open-source way, whenever possible. Building solutions using FOSS lowers the total cost of operations and gives more parties access to contribute to the project. That leaves vendors on equal footing when it comes to maintenance and further development.

FOSS applies especially to pieces of reusable software that can prove useful for other organisations and corporations. E.g. UI components and integrations for our authentication system and Straumurinn (Iceland's X-Road data transfer layer).

Open-sourcing promotes better documentation across the board, which is especially crucial for Digital Iceland and it's teams, as well as external contributors. By supporting external contributions, we can increase the quality of our solutions in many ways, e.g. with better accessibility, translations, browser compatibility and security.

All code used by Digital Iceland needs to have permissive open-source licenses. Vendors agree to release all rights to their work so Digital Iceland can publish it with an open-source license (i.e. the MIT license for code and CC BY 4.0 for documentation).

See more information about FOSS on [the Government of Iceland website](https://www.stjornarradid.is/verkefni/upplysingasamfelagid/stafraent-frelsi/opinn-hugbunadur/).

### Hosting Environment

When we create centralized solutions, we assume more responsibility for keeping systems running and services operational. To handle this responsibility, we need holistic monitoring, alerts and call system, as well as operational dashboards that provide an overview for the whole system. We will also create a status page that is open to the public, to increase transparency, accountability and communications when users encounter operational issues.

By maintaining an incident log and performing root cause analysis, we can implement the fixes needed, in both internal and external systems, to prevent recurrence of production issues.

Digital Iceland will embrace cloud hosting for its solutions. Cloud hosting increases operational stability by hosting backend solutions with high availability on virtualized computers and operating systems. When one computer stops working, another starts automatically. When we receive increased demand, we can spread it on more computers with minimal or no human intervention.

### Localisation

All of Digital Iceland's solutions should have localisation support built-in, with content available in Icelandic and other languages depending on the context.

Digital Iceland looks to the European regulation [Single Digital Gateway](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32018R1724) when it comes to translating content and services. The directive declares services that are relevant to people crossing borders should be available in languages that cover most of its users. In our case, these services will be at least available in Icelandic and English.

### Performance

Research shows that performance is a critical factor for user experience in digital services. Users expect websites to load in two seconds, and after three seconds, [up to 40% of users will abandon the site](http://bit.ly/1ttKspI). As we develop more comprehensive solutions with more services, it is easy to end up with subpar performance.

Digital Iceland will set clear performance goals and encourage periodic performance tests to measure and improve overall performance. These goals apply to page load and interactions on desktop and mobile, API responses, X-Road and more.

### User-centered design

Design solutions with a focus on User Experience (UX). Digital Iceland plans to release a design guide that covers this in more detail. Until then, here are a few things to keep in mind:

* Include designers, UX specialists and testers in the project from the beginning.
* Consider the user in all parts of design and development with personas and user stories.
* Create prototypes and perform user testing to verify the design.
* Design the backend to serve the UX rather than the other way around. Try to overcome system limitation when they hurt the user experience.

### Security

Since Ísland.is solutions will process sensitive, Personally Identifiable Information (PII), it is crucial to have security at the forefront at all stages of development.

Teams should be familiar with the vulnerabilities and attacks documented in the Open Web Application Security Project (OWASP). Digital Iceland will look to the ISO 27001 family of standards when it comes to hosting and operations and requires vendors to perform in-house security assessments.

There will be regular monitoring of all solutions developed by Digital Iceland with security assessments and audits performed by a third party to prevent unforeseen vulnerabilities. Digital Iceland will follow the latest security policies published by the Security Council of the Ministry of Transport and Local Government.


# Technical Implementation

Hi there, you are probably new to the project. Here you can find a quick overview of what you can expect and what is expected from you as a contributor.

## Technology

### General

Our main programming language is [TypeScript](https://www.typescriptlang.org/). TypeScript is a popular programming language which is compiled into JavaScript and offers strict data types, readable code and a compiler that catches many errors. Deep integration in development tools helps teams build and maintain large solutions.

We use [NX](https://nx.dev) to manage the monorepo structure. We have one set of NodeJS modules used by all code and any changes in there affect potentially multiple services.&#x20;

| Tool                                          | Description                          |
| --------------------------------------------- | ------------------------------------ |
| [NodeJS](https://nodejs.org/en/)              | Scripts and server-side framework.   |
| [TypeScript](https://www.typescriptlang.org/) | Programming language.                |
| [NX](https://nx.dev/react)                    | Monorepo tools and code scaffolding. |

### Frontend

When creating interfaces, teams should use the [React](https://reactjs.org/) frontend framework. With React, teams create user interface (UI) components which they then arrange to form complete interfaces.

Many of these UI components can be reused for multiple interfaces, across teams and projects, e.g. buttons, inputs and navigation. Teams should add these to [Storybook](https://storybook.js.org/), which provides an overview of all reusable components, as well as a testing environment for interested stakeholders.

| Tool                                                          | Description                                                 |
| ------------------------------------------------------------- | ----------------------------------------------------------- |
| [React](https://reactjs.org/)                                 | UI framework.                                               |
| [NextJS](https://nextjs.org/)                                 | Front-end framework with routing and server side rendering. |
| [Vanilla Extract](https://vanilla-extract.style/)             | Stylesheets in TypeScript.                                  |
| [Storybook](https://storybook.js.org/)                        | Develop and document React components in isolation.         |
| [Apollo Client](https://www.apollographql.com/docs/react/)    | GraphQL client.                                             |
| [GraphQL Code Generator](https://graphql-code-generator.com/) | Generate GraphQL clients and types.                         |
| [Playwright](https://playwright.dev/)                         | Automated browser testing tool.                             |

### Backend

The backend is also implemented in **TypeScript**, using the [Node.JS](https://nodejs.org/en/about/) framework. By using the same programming language in the frontend and backend, we can share code, e.g. types and validation. The work becomes more efficient, with fewer developer roles since more developers can work on both sides. Node.JS also has a large and active open-source community, with mature code libraries covering most needs.

Backend servers should provide a [GraphQL](https://graphql.org/) interface for frontend clients. It defines a schema that describes all the available data and operations. Whenever possible, the schema should represent an idealised world independent of implementation details. When designed well, it is possible to replace backend systems without changing the schema or frontend.

GraphQL provides better separation between the frontend and backend. In one GraphQL query, the frontend can ask for everything it requires. The GraphQL server calls web services and databases as needed to resolve the query, and the result contains only the data that the frontend requested.

| Tool                                                 | Description                                  |
| ---------------------------------------------------- | -------------------------------------------- |
| [NestJS](https://nestjs.com/)                        | Server-side framework for NodeJS.            |
| [Sequelize](https://sequelize.org/)                  | Database object relational mapper.           |
| [OpenAPI Generator](https://openapi-generator.tech/) | Generate clients and types for OpenAPI APIs. |

### Code Quality

| Tool                             | Description             |
| -------------------------------- | ----------------------- |
| [Jest](https://jestjs.io/)       | Automated testing tool. |
| [ESLint](https://eslint.org/)    | Code checker.           |
| [Prettier](https://prettier.io/) | Code formatter.         |

### Protocols and specifications

| Tool                                           | Description                             |
| ---------------------------------------------- | --------------------------------------- |
| [GraphQL](https://graphql.org/)                | API protocol for our frontend projects. |
| [OpenAPI](https://www.openapis.org/)           | Specification to describe rest APIs.    |
| [Open ID Connect](https://openid.net/connect/) | Authentication protocols.               |

### Code storage and Repositories

The main digital government platform is in a monorepo stored in GitHub. It contains the code for all of its solutions in one code repository with collaboration between all teams.  See more on [monorepo](/technical-overview/monorepo).

| Tool                                                         | Description                                            |
| ------------------------------------------------------------ | ------------------------------------------------------ |
| [GitHub](https://github.com/)                                | Platform to create, store, manage and share code.      |
| [Island.is monorepo](https://github.com/island-is/island.is) | Open source repository for Iceland's digital services. |

### Infrastructure

We host our solutions in a containerised cloud environment, using [Docker](https://www.docker.com/resources/what-container) and [Kubernetes](https://kubernetes.io/), on  [AWS](/development/devops/environment-setup). infrastructure. Applications are composed of services that are [packaged in Docker containers](#dockerizing) and then deployed in a Kubernetes cluster using Helm.  To avoid lock-in, we use open-source databases and tools that we can host on any cloud infrastructure.

With Docker containers, services run independently of the hardware. They are easy to spin up, especially suitable for Agile development with continuous delivery and can handle increased load and hardware problems.

We've configured our cloud environment with a secure virtual private network that limits external access to sensitive services as well as allowing us to set up VPN connections and fixed IP addresses to integrate with external services. We also have an X-Road Security Server to access other government organisations through Straumurinn.

| Tool                                                                                             | Description                                                                                |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| [Docker](https://www.docker.com/)                                                                | Virtual machine containers for continuous integration and deployment.                      |
| [Kubernetes](https://kubernetes.io/)                                                             | Host docker containers in production.                                                      |
| [Helm](https://helm.sh/)                                                                         | Kubernetes deployment configuration.                                                       |
| [X-Road](https://x-road.global/)                                                                 | X-Road is a centrally managed distributed Data Exchange Layer between information systems. |
| [Straumurinn](https://docs.devland.is/technical-overview/x-road/straumurinn-usage-and-operation) | The Icelandic government x-road network.                                                   |

### Content and documentation

<table><thead><tr><th width="473">Tool</th><th>Description</th></tr></thead><tbody><tr><td><a href="https://www.gitbook.com/">Gitbook</a></td><td>Content management for technical documentation.</td></tr><tr><td><a href="https://www.contentful.com/">Contentful</a></td><td>Headless content management system for application's content.</td></tr><tr><td><a href="www.notion.so/">Notion.so</a></td><td>Tool used for internal documentation and task management.</td></tr></tbody></table>

## Practices

To contribute you need to follow the standard [GitHub Pull Request (PR)](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) workflow. When you open a PR, your code will be run through the [CI process](/technical-overview/adr/0002-continuous-integration) automatically. Ask for a [code-review](/technical-overview/code-reviews) and when you get an approval, merge to `main`. Rinse and repeat.

When a code change gets on `main`, that will create Docker containers for all services and everything will get deployed to `Dev` env. For more info please see the [Continuous Delivery process](/development/devops/continuous-delivery).

We expect contributors to deliver the following:

* the business logic
* the tests
* documentation
* [logs](/development/devops/logging)
* [metrics](/development/devops/metrics)

## Starting a new project/application

If you are adding a new application, please follow the instructions [here](/development/generate).

## Dockerizing

You simply need to add an NX target to your service to enable creating a Docker image for it. For more info see [dockerizing](/development/devops/dockerizing).

## Kubernetes

We have developed a DSL to describe a service infrastructure setup. You pretty much only need to add your ingress (optional), environment variables (optional) and secrets (optional) and your service can get deployed to Dev. For more info, please see [Service Configuration](/development/devops/service-setup).


# API Design Guide

This is the home of the API Design Guide published by Stafrænt Ísland as a best practice guide for API development. It should help synchronize the work between developers and make working together easier. The guide covers the relevant design principles and patterns to use so the consumer experience is enjoyable and consistent throughout APIs.

This guide is under constant review and updates will be made over time as new design patterns and styles are adopted.

All feedback is welcomed and encouraged to help make the guide better so please feel free to create pull requests.

## Content

* [Once-Only](/technical-overview/api-design-guide/once-only)
* [Resource Oriented Design](/technical-overview/api-design-guide/resource-oriented-design)
  * [Design flow](/technical-overview/api-design-guide/resource-oriented-design#design-flow)
  * [Resource](/technical-overview/api-design-guide/resource-oriented-design#resources)
* [Naming Conventions](/technical-overview/api-design-guide/naming-conventions)
  * [General](/technical-overview/api-design-guide/naming-conventions#general)
  * [Resources](/technical-overview/api-design-guide/naming-conventions#resources)
  * [Fields](/technical-overview/api-design-guide/naming-conventions#fields)
* [GraphQL Naming Conventions](/technical-overview/api-design-guide/graphql-naming-conventions)
  * [Case styles](/technical-overview/api-design-guide/graphql-naming-conventions#case-styles)
  * [Input objects naming conventions](/technical-overview/api-design-guide/graphql-naming-conventions#input-objects-naming-conventions)
  * [Query naming conventions](/technical-overview/api-design-guide/graphql-naming-conventions#query-naming-conventions)
  * [Mutation naming conventions](/technical-overview/api-design-guide/graphql-naming-conventions#mutation-naming-conventions)
  * [Integrating naming conventions into shared api](/technical-overview/api-design-guide/graphql-naming-conventions#integrating-naming-conventions-into-shared-api)
* [Data Definitions](/technical-overview/api-design-guide/data-definitions)
  * [Text encoding](/technical-overview/api-design-guide/data-definitions#text-encoding)
  * [JSON](/technical-overview/api-design-guide/data-definitions#json)
  * [National identifier](/technical-overview/api-design-guide/data-definitions#national-identifier)
  * [Language and currency](/technical-overview/api-design-guide/data-definitions#language-and-currency)
  * [Date and time](/technical-overview/api-design-guide/data-definitions#date-and-time)
  * [Timestamp data](/technical-overview/api-design-guide/data-definitions#timestamp-data)
* [Data transfer objects](/technical-overview/api-design-guide/data-transfer-objects)
* [Pagination](/technical-overview/api-design-guide/pagination)
  * [PageInfo](/technical-overview/api-design-guide/pagination#pageinfo)
  * [Pagination Query parameters](/technical-overview/api-design-guide/pagination#pagination-query-parameters)
  * [Monorepo library](/technical-overview/api-design-guide/pagination#monorepo-library)
* [Methods](/technical-overview/api-design-guide/methods)
  * [Methods mapping to HTTP verbs](/technical-overview/api-design-guide/methods#methods-mapping-to-http-verbs)
  * [Custom methods (RPC)](/technical-overview/api-design-guide/methods#custom-methods-rpc)
* [REST Request](/technical-overview/api-design-guide/rest-request)
  * [Query parameters](/technical-overview/api-design-guide/rest-request#query-parameters)
  * [Path parameters](/technical-overview/api-design-guide/rest-request#path-parameters)
* [REST Response](/technical-overview/api-design-guide/rest-response)
  * [General](/technical-overview/api-design-guide/rest-response#general)
  * [GET](/technical-overview/api-design-guide/rest-response#get)
  * [POST](/technical-overview/api-design-guide/rest-response#post)
  * [PUT](/technical-overview/api-design-guide/rest-response#put)
  * [PATCH](/technical-overview/api-design-guide/rest-response#patch)
  * [DELETE](/technical-overview/api-design-guide/rest-response#delete)
* [Errors](/technical-overview/api-design-guide/errors)
  * [Response Body](/technical-overview/api-design-guide/errors#response-body)
* [Documentation](/technical-overview/api-design-guide/documentation)
  * [Describe error handling](/technical-overview/api-design-guide/documentation#describe-error-handling)
  * [Provide feedback mechanism](/technical-overview/api-design-guide/documentation#provide-feedback-mechanism)
  * [Example](/technical-overview/api-design-guide/documentation#example)
  * [Setup example](/technical-overview/api-design-guide/documentation#setup-example)
* [Versioning](/technical-overview/api-design-guide/versioning)
  * [Version changes](/technical-overview/api-design-guide/versioning#version-changes)
  * [URLs](/technical-overview/api-design-guide/versioning#urls)
  * [Increment version numbers](/technical-overview/api-design-guide/versioning#increment-version-numbers)
  * [Deprecating API versions](/technical-overview/api-design-guide/versioning#deprecating-api-versions)
* [Security](/technical-overview/api-design-guide/security)
* [Environments](/technical-overview/api-design-guide/environments)
  * [Development](/technical-overview/api-design-guide/environments#development-environment)
  * [Test](/technical-overview/api-design-guide/environments#test-environment-for-providers-of-an-api)
  * [Sandbox](/technical-overview/api-design-guide/environments#sandbox-environment-for-consumers-of-an-api)
  * [Production](/technical-overview/api-design-guide/environments#production-environment)
* [Example Service](/technical-overview/api-design-guide/example)

## Changelog

*Draft 4 - Published 2023-06-07*

* Updated usage of [HTTP status codes](/technical-overview/api-design-guide/rest-response#http-status-codes) to use `204` instead of `404` when resources are not found or not accessible to the user.
* Update [REST Requests](/technical-overview/api-design-guide/rest-request#working-with-sensitive-data) to describe arrays in query parameters and how to handle sensitive data in query and path parameters.
* Update [Custom Methods (RPC)](/technical-overview/api-design-guide/methods#custom-methods-rpc) to use verbs instead of nouns for method names with `POST`.

*Draft 3 - Published 2022-08-16*

* Improving [Documentation](/technical-overview/api-design-guide/documentation).
* Adding description of Content Types in [REST Response](/technical-overview/api-design-guide/rest-response).
* Making `hasPreviousPage` and `startCursor` optional in [Pagination](/technical-overview/api-design-guide/pagination).
* Adding OWASP and IAS reference in [Security](/technical-overview/api-design-guide/security).
* Other small fixes.

*Draft 2 - Published 2021-10-19*

* Changing pagination description

*Draft 1 - Published 2020-08-31*

* Initial relase


# Data Definitions and Standards

## Text encoding

APIs should represent all texts in the [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding.

## JSON

Primitive values MUST be serialized to JSON following the rules of [RFC8259](https://tools.ietf.org/html/rfc8259) and, as stated in the standard, JSON text MUST be encoded using UTF-8 [RFC3629](https://tools.ietf.org/html/rfc3629).

JSON can represent four primitive types *strings*, *numbers*, *booleans*, and *null* and two structured types *objects* and *arrays*. Concepts like [Date and Time](#date-and-time) need to be represented using these types.

## National identifier

Icelandic individuals are uniquely identified by a national identifier called `kennitala`. When referring to this identifier in URIs, requests, or responses, APIs should use the name `nationalId`. Its value is usually represented to users in the form `######-####` but APIs should use the form `##########` at all times.

## Language and currency

* **Languages** - When specifying a language please use the [ISO-639-1](https://www.iso.org/standard/22109.html) (two letter) standard. See: [639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
* **Currencies** - When specifying currency codes please use the [ISO-4217](https://www.iso.org/iso-4217-currency-codes.html) standard. See: [4217 codes](https://en.wikipedia.org/wiki/ISO_4217#Active_codes).
  * **Amount** - Use the format `[0-9]+(.[0-9]+)?` to represent an amount. Separate amount and currency in different fields. Example amount: `1250.23`.

## Date and time

Date and time values should be represented in a string, as described in the [RFC3339](https://tools.ietf.org/html/rfc3339) proposed standard. The standard defines a profile of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) for use in Internet protocols. See: [Section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6) for Date/Time Format.

### Summary for date and time

Date and time should be represented as a string using the format `yyyy-MM-ddThh:mm:ss.sssZ`. Where

* **yyyy** represents year, (four-digits).
* **MM** represents month, (two-digits *01 - 12*).
* **dd** represents day of month, (two-digits *01 - 31*).
* **hh** represents hour, (two digits *00 - 23*).
* **mm** represents minute, (two digits *00 - 59*).
* **ss** represents second, (two digits *00 - 59*).
* **sss** represents a decimal fraction of a second, (one or more digits).
* **Z** represents a time zone offset specified as `Z` (for [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time)) or either `+` or `-` followed by a time expression `hh:mm`.

Icelandic local time can be represented with `Z` because Iceland follows the [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) +00:00 all year round, which is the same as [GMT](https://en.wikipedia.org/wiki/Greenwich_Mean_Time).

Examples:

* `1985-04-12T23:20:50.52Z` represents 20 minutes and 50.52 seconds after the 23rd hour of April 12th, 1985 in [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time).
* `1996-12-19T16:39:57-08:00` represents 39 minutes and 57 seconds after the 16th hour of December 19th, 1996 with an offset of -08:00 from [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) (Pacific Standard Time). Note that this is equivalent to `1996-12-20T00:39:57Z` in UTC.

## Timestamp data

All returned data should contain the field `createdTimestamp` and it's value should be the [date and time](#date-and-time) when the data was created. This is important because of different caching rules and different viewpoints on when data should be considered obsolete.


# Data Transfer Objects

Data transfer objects, or DTOs, are objects used to wrap resource definitions in request/response objects along with additional information.

In a response body, you should return a JSON object, not an array, as a top level data structure to support future extensibility. This would allow you to extend your response and, for example, add a server side pagination attribute.

**Bad response body**

```
[
  { "id": "1", "name": "Einar"   },
  { "id": "2", "name": "Erlendur"},
  { "id": "3", "name": "Valdimar"}
]
```

**Good response body**

```
{
  "users":[
    { "id": "1001", "name": "Einar"},
    { "id": "1002", "name": "Erlendur"},
    { "id": "1003", "name": "Valdimar"},
  ]
}
```


# Documentation

API documentation should be targeted towards the developer that will consume the API. A good documentation is one of the single most important qualities of an API as it can significantly reduce the implementation time for the API consumers. The API provider is responsible for keeping the documentation up to date.

To help with keeping documentation up to date consider using automatic generation tools that during build time can, for example, gather comments in predefined syntax and generate the [Open API Specification](https://swagger.io/specification/) (OAS), this means that the OAS lives bundled with the code and should be easier for developers to maintain.

## Open Api Specification requirements for the API Catalogue

To be able to register a **REST** service to the *API Catalogue* the service **MUST** provide an **OPENAPI 3** service description.

The following fields, not marked as (*Optional*), are required for services to be automatically imported to the *API Catalogue*:

* [`info`](https://spec.openapis.org/oas/v3.1.0#info-object)
  * description: string — short but proper description of the API.
  * version: string — to distinguish API versions following [semantic versioning](https://semver.org/) specification.
  * title: string — descriptive name of the API.
  * contact: object — information on who to contact about an issue with the service.
    * name: string — of the person or a department.
    * url: string (*Optional*) — containing information on the person or department to contact.
    * email: string — fully qualified email.
  * x-category: Array\<string> — What kind of data does this service work with.
    * Possible values: `open`, `official`, `personal`, `health`, `financial`.
    * These values are displayed in the service view.
  * x-pricing: Array\<string> — Cost of using this service.
    * Possible values: `free`, `paid`.
    * These values are displayed in the service view.
  * x-links: object — Links regarding the service.
    * responsibleParty: string — a fully qualified url to an online page containing information about the responsible party/owner of the service. This is linked to in the service view.
    * documentation: string — (*Optional*) a fully qualified url to the API documentation page. This is linked to in the service view.
    * bugReport: string (*Optional*) — a fully qualified url to an online page or form a consumer can report bugs about the service. This is linked to in the service view.
    * featureRequest: string (*Optional*) — a fully qualified url to an online page or form a consumer can ask for a new feature in api service. This is linked to in the service view.

An Open API Specification document MUST also describe the following:

* Uses the [`Example Object`](https://spec.openapis.org/oas/v3.1.0#example-object) to show example path and query parameters, request and response body for each operation.
* Documents all expected HTTP statuses in the [`Response Object`](https://spec.openapis.org/oas/v3.1.0#responses-object), both success and errors.
* Describes all the content types with a [`Media Type Object`](https://spec.openapis.org/oas/v3.1.0#media-type-object) for operations, both requests and responses.
* Orders the [`Parameter Objects`](https://spec.openapis.org/oas/v3.1.0#parameter-object) to list all required parameters before optional.
* Describes the operation's authentication using the [`Security Requirement Object`](https://spec.openapis.org/oas/v3.1.0#securityRequirementObject) or the [`Security Scheme Object`](https://spec.openapis.org/oas/v3.1.0#security-scheme-object) to set the API top-level security.
* Contains the `description` field for all operations, parameters, and schema fields to provide human readable documentation of the corresponding field.

Example can be found [here](#example).

Setup example for NSwag in .NET core can be found [here](#Setup-example).

This picture shows where each OpenApi extension (x-\*) is displayed or linked in the service view. ![openapi-extensions-map](/files/-MW-JENdHNZfGUl6Shd9)

## Describe error handling

Provide information on which HTTP status codes a client consuming your service can expect the API to return, and provide information on application defined errors and how the errors are presented to clients. See [Errors](/technical-overview/api-design-guide/errors) for further details.

## Provide feedback mechanism

Provide users with a way to comment on your documentation. This will help with finding concepts that need further explanation and keeping the documentation up to date.

The field x-links in the OpenAPI schema provides a way to include paths where consumers can provide feedback on the API.

## Example

```yaml
openapi: 3.0.3
servers:
  - url: https://development.my-service.island.is
    description: Development server
  - url: https://staging.my-service.island.is
    description: Staging server
  - url: https://production.my-service.island.is
    description: Production server
info:
  description: |-
    Provides access to an example service that retrieves individuals
  version: 0.0.1
  title: Example service
  termsOfService: ''
  contact:
    name: Digital Iceland
    url: https://stafraent.island.is/
    email: stafraentisland@fjr.is
  license:
    name: MIT
    url: 'https://opensource.org/licenses/MIT'
  x-pricing:
    - free
  x-category:
    - personal
    - official
  x-links:
    documentation: 'https://docs.my-service.island.is'
    responsibleParty: 'https://my-service.island.is/responsible'
    bugReport: 'https://github.com/island-is/island.is/issues/new'
    featureRequest: 'https://github.com/island-is/island.is/issues/new'
paths:
  /individuals:
    get:
      description: |
        Returns all individuals registered
      operationId: getIndividuals
      parameters:
        - name: dateOfBirth
          in: query
          description: Find all individuals born after set date
          required: false
          schema:
            type: string
            format: date
          examples:
            dateOfBirthExample:
              summary: Example of date of birth query parameter
              value: '1930-12-10'
      responses:
        '200':
          description: |
            Returns an array of individuals, either it returns all individuals or individuals born after a specific date
          content:
            application/json:
              schema:
                type: object
                properties:
                  individuals:
                    type: array
                    items:
                      $ref: '#/components/schemas/Individual'
              examples:
                individual:
                  $ref: '#/components/examples/IndividualsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '500':
          $ref: '#/components/responses/InternalServerError'
        default:
          description: Unexpected error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    $ref: '#/components/schemas/Error'
      security:
        - auth:
            - '@myorg.is/individuals:read'
  /individuals/{id}:
    get:
      description: |
        Returns individual based on a single ID
      operationId: getIndividual
      parameters:
        - name: id
          in: path
          description: UUID of an individual
          required: true
          schema:
            type: string
            format: UUID
          examples:
            uuidExample:
              summary: Example of UUID parameter
              value: '0762e29f-edf9-4fb3-b324-4503e92a5033'
      responses:
        '200':
          description: |
            Returns an individual with a specific id
          content:
            application/json:
              schema:
                type: object
                properties:
                  individuals:
                    type: array
                    items:
                      $ref: '#/components/schemas/Individual'
              examples:
                individual:
                  $ref: '#/components/examples/IndividualResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/BadRequest'
      security:
        - auth:
            - '@myorg.is/individuals:read'
components:
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                $ref: '#/components/schemas/Error'
    NotFound:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                $ref: '#/components/schemas/Error'
    InternalServerError:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                $ref: '#/components/schemas/Error'
  schemas:
    Individual:
      type: object
      properties:
        id:
          type: string
          description: Unique UUID
          format: UUID
        nationalId:
          type: string
          minLength: 12
          maxLength: 12
          pattern: '^\d{12}$'
          description: National security number
        firstName:
          type: string
          minLength: 1
          maxLength: 250
          description: First name and middle name
        lastName:
          type: string
          minLength: 1
          maxLength: 250
          description: Last name
        dateOfBirth:
          type: string
          format: date-time
          description: UTC date of birth
      example:
        id: 'BA84DAF1-DE55-40A8-BF35-8A76C7F936F6'
        nationalId: '160108117573'
        firstName: 'Quyn G.'
        lastName: 'Rice'
        dateOfBirth: '2019-03-29T18:00:58.000Z'
        address: '377-8970 Vitae Rd.'
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
        message:
          type: string
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ErrorDetail'
      example:
        code: 400
        message: 'Bad request'
        errors:
          - code: 87
            message: 'Parameter is incorrectly formatted'
            help: 'https://www.moa.is/awesome/documetation/devices'
            trackingId: '5d17a8ada52a2327f02c6a1a'
            param: 'deviceId'
          - code: 85
            message: Parameter missing
            help: 'https://www.moa.is/awesome/documetation/devices'
    ErrorDetail:
      type: object
      required:
        - message
      properties:
        code:
          type: integer
        message:
          type: string
        help:
          type: string
        trackingId:
          type: string
        param:
          type: string
  examples:
    IndividualResponse:
      summary: Example of a response of a single individual
      value:
        id: '0762e29f-edf9-4fb3-b324-4503e92a5033'
        nationalId: '1234567890'
        firstName: 'Doctor'
        lastName: 'Strange'
        dateOfBirth: '1930-12-10T13:37:00.000Z'
        address: '535 West End Avenue at West 86th Street'

    IndividualsResponse:
      summary: Example of a response of array of individuals
      value:
        - id: '0762e29f-edf9-4fb3-b324-4503e92a5033'
          nationalId: '1234567890'
          firstName: 'Doctor'
          lastName: 'Strange'
          dateOfBirth: '1930-12-10T13:37:00.000Z'
          address: '535 West End Avenue at West 86th Street'
        - id: '68c78874-ff03-4ea6-b68d-ceba07286450'
          nationalId: '0987654321'
          firstName: 'Wanda'
          lastName: 'Maximoff'
          dateOfBirth: '1989-02-15T13:37:00.000Z'
          address: 'Sokovia'
  securitySchemes:
    auth:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://identityprovider.is/connect/authorize
          tokenUrl: https://identityprovider.is/connect/token
          scopes:
            '@myorg.is/individuals:read': Read access to the individual api.
            '@myorg.is/individuals:write': Write access to the individual api.
```

## Setup example

```
public void ConfigureServices(IServiceCollection services)
{
	services.AddControllers();
	services.AddRouting(options => options.LowercaseUrls = true);

	services.AddOpenApiDocument(config =>
	{
		//Registers all the required information for the API catalogue
		config.PostProcess = document =>
		{
			//Basic information for the service, what it does and who is responsible for it
			document.Info.Version = "v1";
			document.Info.Title = "National Registry";
			document.Info.Description = "Provides access to an example service that retrieves individuals.";
			document.Info.Contact = new NSwag.OpenApiContact { Name = "Digital Iceland", Email = "stafraentisland@fjr.is", Url = "https://stafraent.island.is/" };

			//The extension fields specifically used for API catalogue to help filter services
			document.Info.ExtensionData = new Dictionary<string, object>();
			document.Info.ExtensionData.Add(new KeyValuePair<string, object>("x-category", new string[] { "personal", "official" }));
			document.Info.ExtensionData.Add(new KeyValuePair<string, object>("x-pricing", new string[] { "free", "paid" }));
			document.Info.ExtensionData.Add(new KeyValuePair<string, object>("x-links", new Dictionary<string, string>()
			{
				{ "documentation", "https://docs.my-service.island.is" },
				{ "responsibleParty", "https://www.skra.is/um-okkur" },
				{ "bugReport", "https://github.com/island-is/island.is/issues/new" },
				{ "featureRequest", "https://github.com/island-is/island.is/issues/new" },
			}));

		};
	});
}
```


# Environments

This document describes different environments and their purpose.

* Development environment
* Test environment (for providers of API)
* Sandbox environment (for consumers of API)
* Production environment

## Development environment

The development environment used to develop APIs should contain set of processes and programming tools to develop functional APIs. The developed assets should be connected to revision control and build processes to create a functional API. The functional API can then be deployed to other test and production environments.

## Test environment (for providers of an API)

The purpose of the test environment is to test new and changed code via either automated checks or non-automated techniques. This is to validate that the functionality of a provided API is correct before moving it to the production and sandbox environments.

This environment is not used by consumers of the API, only providers.

## Sandbox environment (for consumers of an API)

The purpose of the sandbox environment is for consumers/subscribers of an API to test and develop applications using the API. Consumers can then test their application against supported versions of the API.

Data used by an API in a sandbox environment can be either production or synthetic test data.

### Synthetic test data

Synthetic test data does not use any actual data from the production data store and sources. It is artificial data based on the data model for that database. Synthetic test data can be generated automatically by synthetic test data generation.

### Production test data

Production test data is a copy of a production database that has been masked, or obfuscated, and subsetted to represent a portion of the database that is relevant to test the API.

## Production environment

The live system hosting the API. Consumers of APIs use this environment to call APIs with live authentication and actual data.


# Error Handling

This document describes how REST APIs should present errors to clients consuming their services.

When an error occurs in a API, the service should return the error to the calling client in an informative and structured manner. The API should return information about the error in the response body.

## Response Body

When an error occurs, a REST API should respond with an 4xx or 5xx [HTTP status code](/technical-overview/api-design-guide/rest-response) and the response should contain a Problem Details object as described in the [IETF RFC7807 documentation](https://datatracker.ietf.org/doc/html/rfc7807).

### Problem Details Object

For REST APIs the Problem Details object is modelled as a JSON object. The format is identified with the `application/problem+json` content type in the HTTP `Content-Type` header.

The `type` string is the primary problem identifier and is, as such, required. Every other field is optional but it is **HIGHLY RECOMMENDED** to at least have `title` and `status` strings present in the error response.

* `type` *(string)* A URI reference that identifies the problem type. This specification encourages that, when dereferenced, it provides human-readable documentation for the problem type.
* `title` *(string)* **(Optional)** A short human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence.
* `status` *(number)* **(Optional)** The HTTP Status Code generated by the origin server for this occurrence of the problem.
* `detail` *(string)* **(Optional)** A human-readable explanation of the problem. This MAY differ from occurrence to occurrence.
* `instance` *(string)* **(Optional)** A URI reference that identifies the specific occurrence of the problem.
* `extensions` **(Optional)** Any Problem Detail object can contain custom extensions specific to the REST API.
  * `traceId` *(string)* A very common custom extension used to further clarify the context in which the error occurred.
  * `params` *(Array)* A common custom extension used to indicate which parameters were being used when the error occurred.

### REST Error Response Examples

Simple Response

```javascript
{
  "type": "https://example.com/probs/out-of-credit",
  "title": "You do not have enough credit.",
  "status": 403,
  "detail": "Your current balance is 30, but that costs 50.",
  "instance": "/account/12345/msgs/abc"
}
```

Response With Extensions

```javascript
{
  "type": "https://example.com/probs/out-of-credit",
  "title": "You do not have enough credit.",
  "status": 403,
  "detail": "Your current balance is 30, but that costs 50.",
  "instance": "/account/12345/msgs/abc",
  "traceId": "7kHPSP_X0W1R0fo5h0fG",
  "balance": 30,
  "accounts": [
    {
      "owner": 587,
      "path": "/account/12345"
    },
    {
      "owner": 587,
      "path": "/account/67890"
    }
  ]
}
```


# Example API Service

## NodeJS

An example of an API service in NodeJS using the NestJS framework can be found in Stafrænt Ísland's main repository:

> <https://github.com/island-is/island.is/tree/main/apps/reference-backend>


# GraphQL Naming Conventions

This document describes the GraphQL's Naming Conventions

## Case styles

* **Field names** should use `camelCase`. Many GraphQL clients are written in JavaScript, Java, Kotlin, or Swift, all of which recommend camelCase for variable names.
* **Type names** should use `PascalCase`. This matches how classes are defined in the languages mentioned above.
* **Enum names** should use `PascalCase`.
* **Enum values** should use `ALL_CAPS`, because they are similar to constants.

### Examples

```graphql
type Dog {
  id: String!
}

query DogQuery {
  dog {
    id
  }
}

enum Animal {
  DOG
  CAT
}
```

## Input objects naming conventions

Use a single, required, unique, input object type as an argument for easier execution on the client.

```graphql
query DogQuery {
  dog(input: DogQueryInput!) {
    id
  }
}

mutation PetDogMutation {
  petDog(input: PetDogInput!) {
    id
  }
}
```

## Query naming conventions

GraphQL is about asking for specific fields on objects, therefore it's essential that the query has exactly the same shape as the result. Naming queries the same as the type will help with that:

```graphql
query {
  dog {
    id
  }
}
```

will result in:

```graphql
data {
  dog {
    id
  }
}
```

You can make a sub-selection of fields for that object. GraphQL queries can traverse related objects and their fields.

```graphql
query {
  dog {
    id
    owner {
      id
    }
  }
}
```

### Fetching array of items

GraphQL list queries work quite differently from single field queries. We know which one to expect based on what is indicated in the schema, which will be denoted by a `plural` name.

The pagination structure should follow a simplified version of the Relay's connection pattern.

```graphql
query {
  dog {
    id
    owners(first: 10, after: $endCursor) {
      count
      items {
        id
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

## Mutation naming conventions

Make mutations as specific as possible. Mutations should represent semantic actions that might be taken by the user whenever possible.

Name your mutations verb first. Then the object, or “noun,” if applicable; `createAnimal` is preferable to `animalCreate`.

```graphql
mutation {
  createAnimal(input: CreateAnimalInput!) {
    id
  }
}
```

## Integrating naming conventions into shared api

**Now for the hard part!**

Since all of our `resolvers` will be merged into a shared `api`, we need to come up with a system to avoid overwriting previous resolvers. Let's take this example to understand the problem better.

We have two projects, `ProjectX` and `ProjectY`. Both of these projects need to query a `user`, but the user type references a different resource.

1. `ProjectX`'s resolvers are merged first with the `user` query that fetches users from the `National Registry`.
2. `ProjectY`'s resolvers are merged after with the `user` query that fetches users from the `RSK`.

Here the `ProjectY`'s user query will overwrite the `ProjectX`'s query and will break `ProjectX`.

### Solution

We need to prefix all `Mutations`, `Queries`, `Types`, `Scalars`, etc. with the name of the module that is merged into the `api`.

Mutations should still follow the verb first rule. Then the module name, following the object, or “noun,” if applicable.

#### Exception to the solution

If the name of the GraphQL type/query/mutation is the same as the module, then we don't need the prefix.

#### Example

```graphql
type ProjectXUser {
  id: String!
}

query {
  projectXUser {
    id
  }
}

mutation {
  createProjectXUser {
    id
  }
}
```

```graphql
# here we are working in the identity module, thus we won't name our type IdentityIdenty. Same exception applies for query/mutation

type Identity {
  id: UUID!
}

query {
  identity {
    id
  }
}

mutation {
  createIdentity {
    id
  }
}
```

## Conclusion

With these design principles you should be equipped to design an effective GraphQL system for your API.


# Methods

Methods are operations a client can take on resources. Follow [resource-oriented design](/technical-overview/api-design-guide/resource-oriented-design) when developing methods for APIs. Emphasize resources (data model) over the methods performed on the resources (functionality). A typical resource-oriented API exposes a large number of resources with a small number of methods.

Most API services support the following 5 operations: `LIST`, `GET`, `CREATE`, `UPDATE`, and `DELETE` on all resources, also known as the **standard methods** ([CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)). Create **custom methods** to provide a means to express arbitrary actions that are difficult to model using only the **standard methods**.

A photo album service, for example, may provide the following methods:

| Method                          | Resource                                                  |                                    |
| ------------------------------- | --------------------------------------------------------- | ---------------------------------- |
| `CREATE` *Creates a user*       | `//my-service.island.is/v1/users`                         | a collection of `User` resources   |
| `GET` *Gets a user*             | `//my-service.island.is/v1/users/:userId`                 | a single `User` resource           |
| `UPDATE` *Updates a user*       | `//my-service.island.is/v1/users/:userId`                 | a single `User` resource           |
| `LIST` *Lists photos of a user* | `//my-service.island.is/v1/users/:userId/photos`          | a collection of `Photos` resources |
| `DELETE` *Deletes a photo*      | `//my-service.island.is/v1/users/:userId/photos/:photoId` | a single `Photo` resource          |

For obvious reasons, operations `CREATE` and `LIST` always work on a resource collection, and `GET`, `UPDATE` and `DELETE` on a single resource. **Note:** *You should never define a method with no associated resource*.

## Methods mapping to HTTP verbs

In HTTP RESTful API services, each method must be mapped to an HTTP verb ([HTTP request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)).

The following table specifies the mappings between standard and custom methods and HTTP verbs:

| Method   | HTTP Request Method (Verb) |
| -------- | -------------------------- |
| `LIST`   | `GET`                      |
| `GET`    | `GET`                      |
| `CREATE` | `POST`                     |
| `UPDATE` | `PATCH`/`PUT`              |
| `DELETE` | `DELETE`                   |
| `Custom` | `POST` (usually)           |

## Custom methods (RPC)

APIs should prefer standard methods over custom methods. However, in the real world there is often a need to provide custom methods. A custom method is an action that does not cleanly map to any of the standard methods. The way to add custom methods to your API is to use `POST` and add the verb of the action as a sub-resource.

### Example

An API has a `Message` resource and it provides the standard [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) methods like:

```
GET    https://api.island.is/v1/messages
GET    https://api.island.is/v1/messages/:messageId
POST   https://api.island.is/v1/messages
PUT    https://api.island.is/v1/messages/:messageId
DELETE https://api.island.is/v1/messages/:messageId
```

Then there is a requirement to provide a functionality to be able to archive and unarchive a single message and a batch of messages. The archiving and unarchiving of a single message is then provided by:

```
POST   https://api.island.is/v1/messages/:messageId/archive
POST   https://api.island.is/v1/messages/:messageId/unarchive
```

The batch archiving is provided by

```
POST   https://api.island.is/v1/messages/archive
POST   https://api.island.is/v1/messages/unarchive
```

*Note:* The `POST` method accepts a list of message Ids in the request body.


# Naming Conventions

This document describes API naming conventions related to services and resources, with focus on the general consumer experience. Consistency and clear naming conventions are key to providing uniform APIs between agencies. *For further information about our naming conventions for the developer experience please refer to our* [*coding standard*](/technical-overview/code-standards)*.*

## General

In order to provide a consistent consumer experience across the API ecosystem and over a long period of time, all names used by an API should be:

* simple
* intuitive
* consistent

One goal of these naming conventions is to ensure that the majority of consumers can easily understand an API. It does this by encouraging the use of a simple, consistent and small vocabulary when naming methods and resources. It also enforces names to be in British English. Developers should use our [glossary](/reference/glossary) when in trouble finding the appropriate English translation of an Icelandic concept.

Commonly accepted short forms or abbreviations of long words may be used for brevity. For example, API is preferred over Application Programming Interface. Use intuitive, familiar terminology where possible. For example, when describing removing (and destroying) a resource, delete is preferred over erase. Use the same name or term for the same concept, including for concepts shared across the ecosystem.

Name overloading should be avoided. Use different names for different concepts. Overly general names that are ambiguous within the context of the API and the larger API ecosystem should be avoided as they can lead to a misunderstanding of API concepts. Specific names that accurately describe the API concept and distinguish it from other relevant concepts should be used. There is no definitive list of names to avoid, as every name must be evaluated in their context.

**Bad**

```
Info        // info about what?
Service     // service for what?
Application // application for what?
```

**Good**

```
OrderStatus    // Info about Order status
OrderService   // Service that works with the Order resource
PaternityLeave // Application data for paternity leave application
```

Carefully consider using names that may conflict with keywords in common programming languages. Such names may be used but will likely trigger additional scrutiny during API review. Use them judiciously and sparingly.

## Resources

Resource names should be `singular noun` and use `PascalCase`.

**Bad**

```
Users
user
Paternityleave
```

**Good**

```
User
PaternityLeave
```

### URIs

The [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) defined in [RFC3986](https://tools.ietf.org/html/rfc3986) consists of five components: scheme, authority, path, query and fragment.

```
https://example.com:8042/over/there?name=ferret#nose
\___/   \______________/\_________/ \_________/ \__/
  |            |            |            |        |
scheme     authority       path        query   fragment
```

When structuring resource URIs please follow the following rules:

* \[Resource names and collection IDs] must be the plural form of the singular noun used for the resource.
* Use lowercase letters for URI paths since capital letters can sometimes cause problems.
* Use hyphens (`-`) to improve readability of concatenated resource names.
* Use the forward slash (`/`) in a path to indicate hierarchical relationship between resources.
* Do not end a path with a trailing forward slash (`/`).
* Do not use underscores (`_`) as they can be partially obscured or hidden in some browsers or screens.
* For naming query parameters please use the camelCase naming convention.

Example URI of an authority and a path component

```
example.com/v1/users/1/photos/121
\_________/ |  \___/   \____/ \_/
    |       |    |        |    \
    |       |    |        |      Resource ID
    |       |    |        |         (type)
    |       |    |         \
    |       |    |           Collection ID
    |       |    |              (type)
    |       |     \
    |       |      Resource name of parent resource
    |        \
    |          Major version
      \
        API service name
```

## Fields

Resource field names should be clear, descriptive and use `camelCase`. Fields representing arrays or lists should be named as *plural nouns*.

**Bad**

```yaml
User:
  type: object
  properties:
    Name:
      type: string
    DisplayName:
      type: string
    dspName:
      type: string
    Email:
      type: string
    child:
      type: array
```

**Good**

```yaml
User:
  type: object
  properties:
    name:
      type: string
    displayName:
      type: string
    email:
      type: string
    childs:
      type: array
```

## References

* [Google](https://cloud.google.com/apis/design/naming_convention)
* [restfulapi.net](https://restfulapi.net/resource-naming/)


# Once Only Principle

The [Once Only Principle](https://ec.europa.eu/cefdigital/wiki/display/CEFDIGITAL/Once+Only+Principle) is an e-government concept that aims to ensure that citizens, institutions, and companies only have to provide certain standard information to the authorities and administrations once. By incorporating data protection regulations and the explicit consent of the users, the public administration is allowed to re-use and exchange the data with each other. The once-only principle is part of the European Union's (EU) plans to further develop the Digital Single Market by reducing the administrative burden on citizens and businesses.

* Public service customers (citizens, institutions, and companies) should not have to supply the same information more than once to public administrations.
* **APIs should store collected data in a single database**. That means for example when a service is enriching existing data from another database it should store the enriched data in it's own database, with only a linkable identifier to the existing data.

## References

* [Connecting Europe Facility](https://ec.europa.eu/cefdigital/wiki/display/CEFDIGITAL/Once+Only+Principle)
* [Wikipedia](https://en.wikipedia.org/wiki/Once-only_principle)


# Pagination

All services should support pagination from the start, even though the dataset is small. It is harder to add it later on as it would introduce breaking changes to the service interface.

Pagination should be implemented using *Cursor* as a page reference. Cursor pagination solves the missing or duplication of data problems that the typical offset method has. Cursor pagination returns a cursor in the response, which is a pointer to a specific item in the dataset. This pointer needs to be based on an unique sequential field (or fields).

When implementing a cursor pagination the response object should follow this interface:

```typescript
interface GetReponse {
  data: T[]
  pageInfo: {
    hasPreviousPage?: boolean
    hasNextPage: boolean
    startCursor?: string
    endCursor: string
  }
  totalCount: number
}
```

The name of the data fields is arbitrary, and the developer is free to choose more descriptive name like in the following example:

```json
{
  "users":[
    { "id": "1001", "name": "Einar"},
    { "id": "1002", "name": "Erlendur"},
    { "id": "1003", "name": "Valdimar"},
  ],
  "pageInfo": {
    "hasNextPage": true,
    "hasPreviousPage": false,
    "startCursor": "aWQ6MTAwMQ=="
    "endCursor": "aWQ6MTAwMw==",
  },
  "totalCount": 25
}
```

The `totalCount` field indicates how many total items are available on the server.\
The `PageInfo` object is described in the following [section](#pageinfo).

## PageInfo

The `PageInfo` contains details about the pagination. It should follow the interface:

```typescript
interface PageInfo {
  hasPreviousPage?: boolean
  hasNextPage: boolean
  startCursor?: string
  endCursor: string
}
```

The `hasPreviousPage` and `startCursor` are optional but should be provided. The `hasPreviousPage` and `hasNextPage` are boolean flags to indicate if there exists more items before or after the current set of data received. The `startCursor` and `endCursor` are `Base64` encoded strings. The client uses these values in following request to get previous or next page, see [query parameters](#pagination-query-parameters).

## Pagination Query parameters

For an API to support pagination it needs to support the following query parameters:

* `limit` - Limits the number of results in a request. The server should have a default value for this field.
* `before` - The client provides the value of `startCursor` from the previous response `pageInfo` to query the previous page of `limit` number of data items.
* `after` - The client provides the value of `endCursor` from the previous response to query the next page of `limit` number of data items.

The client only sends either `before` or `after` fields in a single request indicating if it wants the previous or next page of data items.

## Monorepo library

[Island.is monorepo](https://github.com/island-is/island.is) provides a [library](https://github.com/island-is/island.is/tree/main/libs/nest/pagination) which contains DTO object for `PageInfo` and `Pagination` query objects. The library also contains an extension for paginated Sequelize queries.


# Resource Oriented Design

API structure should follow Resource Oriented Design, which should facilitate simpler and more coherent web service interfaces, that should be easy to use and maintain. The data (resource) should control the design of the service, as the data is the key player and the service is centered around making the data accessible.

## Design flow

The fundamental idea is that the basic, well-understood, and well-known technologies of the current web (HTTP, URI and XML) should be used according to their design principles. This facilitates the design of web services that have simple and coherent interfaces, and which are easy to use and maintain. Such web services will also be easier to optimize for working with the existing infrastructure of the web.

The Resource-Oriented Architecture (ROA) consists of four concepts:

* Resources.
* Their names (URIs).
* Their representations.
* The links between them and the four properties:
  * Addressability.
  * Statelessness.
  * Connectedness.
  * A uniform interface.

The Design Guide suggests taking the following steps when designing resource- oriented APIs.

* Determine what types of resources an API provides.
* Determine the relationships between resources.
* Decide the resource name schemes based on types and relationships.
* Decide the resource schemas.
* Attach a minimum set of [methods](/technical-overview/api-design-guide/methods) to resources. Use the standard methods(verbs) as much as possible.

## Resources

A resource-oriented API is generally modelled as a resource hierarchy, where each node is either a simple resource or a collection resource. For convenience, they are often called a resource and a collection, respectively.

* A collection contains a list of resources of the same type. For example, a user has a collection of photos.
* A resource has some state and zero or more sub-resources. Each sub-resource can be either a simple resource or a collection resource.

A resource name consists of the resource’s type, its identifier, the resource name of its parent and the name of the API service. The type is known as the **Collection ID**, and the identifier is known as the **Resource ID**. Resource IDs are usually random strings assigned by the API service, though it is also OK to accept custom resource IDs from clients. **Collection IDs must be the plural form of the noun used for the resource and Resource IDs should be immutable**.

Below are two examples of valid resource names:

User

```
my-service.island.is/v1/users/1
\__________________/ | \____/ |
         |           |   |    |
         |           |   |     \
         |           |   |      Resource ID
         |           |    \
         |           |     Collection ID
         |           |        (type)
         |            \
         |             Major version
         \
          API service name
```

Photo

```
my-service.island.is/v1/users/1/photos/1
\__________________/ | \____/  \_____/ |
          |          |    |       |    |
          |          |    |       |     \
          |          |    |       |      Resource ID
          |          |    |       |        (type)
          |          |    |        \
          |          |    |         Collection ID
          |          |    |            (type)
          |          |     \
          |          |      Resource name of parent resource
          |           \
          |            Major version
          \
           API service name
```

## References

* [Google: Resource Oriented Design](https://cloud.google.com/apis/design/resources)
* [Ratros Y: Designing APIs](https://medium.com/@ratrosy/designing-apis-4eed43409f93)


# REST Request

## Query parameters

### Arrays

When passing arrays as query parameters, the array should be passed as a repeated query parameter with the same name.

For example:

```http
https://api.example.com/v1/users?ids=1&ids=2&ids=3
```

### Sensitive data

When making GET requests we sometimes need to pass sensitive data as query parameters. To avoid it being logged by monitoring systems it should not be included in the request URL as normal non-sensitive parameters. Instead, we should use HTTP Request headers to pass the data in the request.

The header name should be prefixed with `X-Query-` and the name of the query parameter, for example `X-Query-National-Id`.

For example instead of:

```http
https://api.example.com/v1/users?nationalId=1234567890
```

do:

```http
https://api.example.com/v1/users

// Headers section
X-Query-National-Id: 1234567890
```

## Path parameters

### Sensitive data

When working with a REST resource where the resource ID is sensitive, it should not be included in the URL path. Instead, it should be passed as a HTTP Request header in the request.

{% hint style="info" %}
An API should prefer non-sensitive IDs like GUIDs as resource IDs.
{% endhint %}

A placeholder is needed in the URL path instead of the sensitive resource ID. The placeholder should be prefixed with a dot (`.`) and the name of the path parameter, for example `.national-id`. The header name should be the name of the path parameter prefixed with `X-Param-`, for example `X-Param-National-Id`.

For example instead of:

```http
https://api.example.com/v1/users/1234567890
```

do:

```http
https://api.example.com/v1/users/.national-id

// Headers section
X-Param-National-Id: 1234567890
```


# REST Response

A REST API should use an appropriate HTTP Status Code and Content Type when responding to a client's request.

## Content Type

An API can support multiple response content types. It's preferred to use a JSON content type by default. When an API supports multiple content types the client can specify the desired content type with the [`Accept` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept).

The following table shows a list of common content types:

| Content Type                                                            | Description                                                                                                                      |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| [application/json](https://www.rfc-editor.org/rfc/rfc8259)              | **Default.** Content type for a JSON response body.                                                                              |
| [application/problem+json](https://www.rfc-editor.org/rfc/rfc7807.html) | Content type for the [Problem JSON error object](/technical-overview/api-design-guide/errors) for `4xx` and `5xx` statuse codes. |
| [application/xml](https://www.rfc-editor.org/rfc/rfc7303#section-9.1)   | Content type for a XML response body. Should be used when the XML is unreadable by casual users.                                 |
| [text/xml](https://www.rfc-editor.org/rfc/rfc7303#section-9.2)          | Content type for a XML response body. Should be used when the XML is readable by casual users.                                   |

{% hint style="info" %}
When more details are needed in an error response the API should use an application defined errors and supply them in an [error object](/technical-overview/api-design-guide/errors) in the response body.
{% endhint %}

{% hint style="info" %}
In previous version of XML [RFC3023](https://www.rfc-editor.org/rfc/rfc3023) it said that `text/xml` was intended for XML content which a casual user is able to read, while `application/xml` is preferred when the XML content is unreadable by casual users.
{% endhint %}

## HTTP Status Codes

REST APIs should use the range of [`HTTP Status Codes`](https://httpstatuses.org/) to give the clients the most appropriate result of the request processing.

An API should at least use the following HTTP Status Codes for corresponding HTTP methods:

| Code | Meaning      | GET | POST | PUT | PATCH | DELETE |
| ---- | ------------ | :-: | :--: | :-: | :---: | :----: |
| 200  | OK           |  X  |      |  X  |   X   |    X   |
| 201  | Created      |     |   X  |     |       |        |
| 202  | Accepted     |     |   X  |     |       |        |
| 204  | No Content   |  X  |      |  X  |   X   |    X   |
| 303  | See Other    |     |   X  |     |       |        |
| 400  | Bad Request  |     |   X  |  X  |   X   |        |
| 401  | Unauthorized |  X  |   X  |  X  |   X   |    X   |
| 403  | Forbidden    |  X  |   X  |  X  |   X   |    X   |
| 404  | Not Found    |  X  |   X  |  X  |   X   |    X   |
| 500  | Server error |  X  |   X  |  X  |   X   |    X   |

## General

* `401` should be returned when client fails to authenticate.
* `403` should be returned when client is authenticated but does not have necessary permission to perform the operation.
* `404` should be returned when the static path of the request does not exist on the server.
* `500` should be returned when the server encounters some unexpected error, preferably along with an [errors](/technical-overview/api-design-guide/errors) object.

## `GET`

For retrieving a resource or a collection of resources.

* `200` should be returned on success. If a collection asked for is empty or user does not have permission to access it, `200` is still to be returned with and empty array.
* `204` should be returned when a single resource requested does not exist or the user does not have permission to access it.

{% hint style="info" %}
When a parent resource of a sub-resource collection is not found or user does not have sufficient permissions the request should return `204` response.
{% endhint %}

## `POST`

For creating a resource.

* `201` should be returned when the resource was created. The response body should contain the created resource.
* `202` should be returned when the request has been accepted for processing but may not have been acted upon or completed yet.
* `303` should be returned if the resource already exists on the resource server. The response should contain the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location) header with the URI of the existing resource.
* `400` should be returned if the request is invalid, i.e. the resource already exists or contains invalid fields.

## `PUT`

For updating a existing resource.

* `200` should be returned when resource is successfully updated with the updated resource in the response.
* `204` should be returned when the resource is not found or the user does not have permission to update it.
* `400` should be returned when the request is invalid, i.e. the resource contains invalid fields.

## `PATCH`

For making a partial update on a resource.

* `200` should be returned when resource is successfully updated with the updated resource in the response.
* `204` should be returned when the resource is not found or the user does not have permission to update it.
* `400` should be returned when the request is invalid, i.e. the resource contains invalid fields.

## `DELETE`

For removing a resource.

* `200` should be returned when the resource is deleted and there is a need for a content in the response.
* `204` should be returned when the resource is deleted, does not exist or the user does not have permission to delete it and there is no content in response.


# Security

## OWASP Top 10

The OWASP Foundation is known for its top ten web application security risks. Now the foundation has also collected the top ten security considerations for API projects.

Developers should know of and review these items regularly against their APIs.

<https://owasp.org/www-project-api-security/>

## Authentication & Authorisation

island.is provides a Authentication Service, see its documentation for further details on authentication flows and authorisation of endpoints.

<https://docs.devland.is/technical-overview/auth>


# Versioning

Versioning APIs is necessary to ensure the possibility of continuous development of API services. All APIs must provide a major, minor and patch version numbers. The **major** version number must be included as the first part of the URI path for all APIs.

## Version changes

Developers should strive to make all changes backwards compatible (non-breaking changes).

Versioning APIs should follow the [semantic versioning](https://semver.org/) specification. Given a version number MAJOR.MINOR.PATCH, increment the:

1. MAJOR version when you make incompatible API changes,
2. MINOR version when you add functionality in a backwards compatible manner, and
3. PATCH version when you make backwards compatible bug fixes.

When a `major` version is incremented, a new instance of the API service must be made available and the older version instance kept running as described in section [Deprecating API versions](#deprecating-api-versions).

## URLs

In all URLs with no exceptions, APIs must expose the **major** version number, with the character `v` as a prefix. The **minor** and **patch** version numbers should not be exposed in URLs.

**Bad**

```
https://my-service.island.is/users
https://my-service.island.is/users?v=1
https://my-service.island.is/users?version=1
https://my-service.island.is/v1.2/users
https://my-service.island.is/v1.2.3/users
```

**Good**

```
https://my-service.island.is/v1/users
```

## Increment version numbers

If an API introduces a breaking change, such as removing or renaming a field, its `major` version number must be incremented to ensure that existing user code does not suddenly break. Incrementing the `major` version should be avoided whenever possible to avoid increasing maintenance and cost of running many versions of the same service.

For **GraphQL** APIs use the `@deprecated` directive on fields which are to be renamed or removed from schemas. Add a descriptive text in the `reason:` with information on what the client should use in the future. This will allow older clients to continue functioning while updated clients can get the new schema right away. See [here](https://www.netlify.com/blog/2020/01/21/advice-from-a-graphql-expert/#designing-a-schema-that-is-easy-to-evolve) for more details.

## Deprecating API versions

When there are more than one running instances of an API, the old versions need to be decommissioned at some time to reduce maintenance costs.

### Notify clients when a specific API version will be discontinued

You should notify clients, who use your service, that the old version will stop working at a specified date. You should give them a link to a new version of the service and provide them with information about all breaking changes between versions. To help with that, you should always provide release notes with every version bump.

The specified date must not be less than 6 months from the time you notify your last client. Exceptions from this rule can be made when you see via your logs that no calls to this API version are made anymore.


# Ísland.is Public Web Data Flow

When a user visits <https://island.is>, the picture below roughly describes how the data flows through different systems and eventually gets returned back to the user as a web page.

<figure><img src="/files/wxMBYF4espx1m0hL1qUN" alt=""><figcaption></figcaption></figure>

1. We are using Cloudfront as our CDN. There we cache HTML responses, which means if a user requests a page that's found in cache, then Cloudfront will immediately answer with a cached response instead of forwarding that request to the "web".
2. Web is a Next.js server that gets it's data from the api server via GraphQL endpoints.
3. Api is a monolithic server that is essentially a gateway for Digital Iceland frontends. \
   Developers have a choice whether they'd like to cache GraphQL endpoints and for how long that cache lasts. You can add a special `?bypass-cache=<bypass-secret>` query parameter to the end of the browser url to bypass both the CDN cache and the server cache. \
   Data gets fetched from Contentful or Elasticsearch, depending on whether we are getting single entries or searching/filtering.
4. Contentful is the CMS for the Ísland.is project and acts as the "source of truth" for our data.
5. Search-indexer is a service that syncs data from Contentful into Elasticsearch. When content changes in the CMS then a webhook calls the search-indexer and it syncs the updated data into Elasticsearch.
6. Elasticsearch is used as a search engine for the web. Content gets synced fom Contentful into Elasticsearch via the search-indexer.


# Code Reviews

Code reviews are a valuable tool for improving code quality and sharing knowledge across the teams working on the codebase. There are tons of best practices available online, but over time each company (or as in this case a swarm of companies working in the same codebase) adopts practices which suits their needs and culture.

## Culture

Code reviews lose all their value if nobody feels motivated to comment on code that they feel needs improvements or further explaining, or if these comments have a negative effect on the programmer who committed the code.

Reviews should be concise and written in neutral language. Critique the code, not the author. When something is unclear, ask for clarification rather than assuming ignorance.

There are many programmers contributing to this repository, people who have different backgrounds, culture and personalities. It is very likely that without a common code review etiquette, people will receive comments on their pull requests that might offend them, when the commenter meant no harm, or accidentally chose some unfortunate words.

To minimize the likelihood of this happening we want to apply the following language when reviewing code committed by programmers you do not know:

* Start comments with `Consider:` where you want to share knowledge, or do not have a strong opinion on if this change is necessary in order to get an approval for the pull request.
* Start comments with `Should:` where the code in question should be changed because it is buggy, has some dangerous side effect or introduces a bad performance hit. These types of comments often spark a discussion, so try to keep it positive and rational. If you cannot back this comment on with meaningful arguments, you *should* not have made this comment to begin with.

## Code Coverage

Code coverage is a measurement used to express which lines of code were executed by a test suite.

Code coverage is measured by the test runner which can be configured to generate a coverage report at the end of a test run.

Even though the coverage report can be viewed in a browser by itself it is quite limited.

To enhance the experience we use a code coverage tool called [Codecov](https://about.codecov.io/).

The main features are listed below and instructions on how to use them.

### Dashboard

The [Codecov dashboard](https://app.codecov.io/gh/island-is/island.is/) shows us an aggregated coverage report of all the apps and libraries in the monorepo.

### Pull request comments

The be able to read through a Codecov pull request comment we need to understand Codecov's coverage diff and calculations regarding hits, misses and partials. See the [documentation](https://docs.codecov.com/docs/codecov-delta) for details.

Basically hits are lines are covered by tests, misses are lines that are not covered with tests and partials are lines partially covered with tests.

To calculate the coverage ratio we do `hits / (hits + misses + partials)`

Here is a [coverage diff](https://docs.codecov.com/docs/coverage-diff) to use as a reference while trying out these calcuations.

### Merge checks

Currently merge checks are not configured.


# Code Standards

We use [Prettier](https://prettier.io/) and [ESLint](https://eslint.org/) to automatically enforce most of our Code Standards. Most of our rules follow recommendations from both project with these additions and changes:

* Prettier is configured with single quotes, no semicolons, arrow parens and all trailing commas.
* ESLint is configured to catch likely errors but otherwise provide warnings to encourage best practices without stopping the developer.The base configuration comes from [NX](https://nx.dev/).

Code standard changes can be proposed to the larger team in discipline meetings. For any new rule, we should try to enforce it automatically, even if it means creating a new ESLint rule from scratch.

## Usage

We have commands available to run your code against theses code standard:

* To [format](/development/getting-started#formatting-your-code) your code.
* To [lint](/development/getting-started#running-lint-checks) your code.

## Language

All code, documentation and API interfaces should be written in British English. This makes the project more inclusive, and reduces awkward mixing of languages.

This can be challenging when dealing with government domain words. However, the goal is to provide all of our services in English as well as Icelandic, so we need to find good translations anyways.

When in doubt, check out the [Glossary](/reference/glossary). If something is missing from it, you can ask for suggestions in the team. Just remember to add any new translations to the Glossary.

When integrating with a web service that has its interface in Icelandic, all endpoints and fields should be translated to and from English in the integration layer, so other parts of the system can use English-language objects and functions.

### Fail

```typescript
const kennitala = '...'

const typeDefs = gql`
  Mutation {
    applyForVegabref: VegabrefPayload!
  }
`
```

### Pass

```typescript
const nationalId = '...'

const typeDefs = gql`
  Mutation {
    applyForPassport: PassportPayload!
  }
`
```


# Monorepo

The [Technical Direction](/) lays out a directive that front facing solutions of island.is is to be developed in a monorepo. This follows best practices from companies like Google, Facebook and Microsoft that operate large scale applications across thousands of developers with monorepos.

## Why?

Why do big companies like to manage their code in monorepos, or in other words, use a single code base to manage multiple apps and libraries. The simple answer is that this approach helps manage complexity by applying best practices organization wide. This delivers consistency and predictability in our code, while also maximising the ability to share code between projects.

### Best practices

In monorepos, it is easier to configure code validation and tests that is performed for all projects. Teams work together across projects to discuss and implement best practices, which increases the overall consistency and quality of the code.

For example, shared `prettier` and `eslint` configurations enforce that all code has the same style and follow the same rules.

### Code sharing

In multi-repo systems, there is always an overhead to reusing code. It involves creating new repositories with significant boilerplate, publishing packages into package registries, dealing with versioning and managing changes that cross multiple repositories.

This overhead hurts the amount of code sharing between projects. This affects not only reuse of obvious things like utilities and components, but also testing helpers, CI logic, CD pipelines, code generators and more.

In a monorepo, we can move any piece of code into a shared package and immediately start reusing it.

It's also much easier to make changes to shared code in a monorepo, since we can find and test all usage, with most changes automatically verified in CI. Compared to a multi-repo setup where we need to version every change, where different projects end up depending on different versions of the package, and need to manually update, which gets more risky the farther they fall behind.

### Less code rot

When projects live in their own repositories, its code is mostly seen by its maintainers. When they move on, the code usually lies untouched and starts to rot, where it falls behind on best practices and dependencies.

When it depends on older versions of libraries and components, at best it has inconsistent design and logic from newer projects, at worst it can have major security issues.

Making changes to an old project is difficult when it isn't consistent with newer projects. It takes longer to get into the project, and it requires complex effort/value/risk evaluation between working in the old environment vs upgrading the project in parts or whole.

In a monorepo, best practices, dependencies and shared code are updated for all projects at the same time.

## How?

In the previous sections we've enumerated many of the long term benefits of using monorepos. However, they skimp on the challenges of monorepos. The good news is that how we deal with these challenges brings even more benefits.

### CI/CD

When all projects, old and new, are constantly kept up to date with best practices, shared code and dependencies, we need a high degree of confidence that nothing breaks when we change something.

Also, we need to know which projects are affected by a change and should be deployed. I.e. we don't want to deploy all projects when someone pushes a change `README.md`.

This is where automatic testing and a smart CI/CD setup comes in.

All code should be strongly typed with TypeScript, so we can verify that interfaces and schemas match between projects and dependencies. Depending on the code, it needs to have unit tests, integration tests, contract tests or E2E tests to verify that everything works. This includes our web-apps, which should have Cypress E2E tests that verify primary flows.

The CI runs these tests on every change. By using a monorepo tool that provides a caching layer and tracks dependency graphs, the CI can be optimised to only test projects which are affected by a change. This also allows us to deploy only the projects that are affected by a change.

### Sharing NPM dependencies

Across all of our projects we should strive to have as few dependencies as possible with as few versions as possible. This is important not only for consistency and security but also for performance, especially in web-apps where it's easy to end up with huge bundles of redundant dependencies. So we should try to end up with one ORM, one date manipulation library, one form library etc.

These are [Architectural Decisions](/technical-overview/adr) that need to be well documented. It's completely fine, and expected, that these decisions don't last forever. When we decide on a specific dependency, we'll have a migration period during which the monorepo is using different dependencies for the same task. The important thing is to have a direction and a plan.

To enforce this, we have a single package.json in the root of the monorepo, which lists all dependencies for all projects. Having a single package.json eliminates a lot of issues when multiple projects depend on different versions of the same package, including having redundant code in website bundles.

### Code ownership

Even though all code is in the same repository, it is important to set virtual boundaries. Teams should be free to work on code for their own projects. If they need to modify other code, especially shared code, those changes should be reviewed by other teams.

Generally project code is owned by the teams working on the project while shared code is managed by specific teams or [Disciplines](/technical-overview/teamwork#disciplines).

Using [Protected Branch](https://help.github.com/en/github/administering-a-repository/about-protected-branches) and [Code Owner](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners) features in GitHub, we can enforce code ownership on a file and folder level. Each pull request automatically notifies and requests reviews from the teams responsible for the changed code. These pull requests can not be merged unless they are reviewed by the respective parties.

## Branching strategy

We use [OneFlow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow) to organise branches during feature development and release management.

Everything on main should be stable and ready for release.

Work is performed on feature branches, which need to pass Continuous Integration checks and code reviews before they can be merged to main. Larger features can be managed in two ways:

1. If the feature is isolated and unlikely to have conflicts, it can be developed on a long-lasting feature branch until it is ready for deployment.
2. If the feature touches a lot of code and is likely to have conflicts, we should try to split it into smaller feature branches that are reviewed and merged independently. The overall feature can be disabled in production, eg using feature flags.

We use "squash and merge" to compress features into one commit on main. This gives us a clean git history and allows us to easily revert unstable features.

When it's time to deploy to production, we create a release branch from main. There we can test, approve and hotfix the release without blocking main. When a release goes live, we tag the release branch and merge it to main.

If we need to deploy a hotfix to production, we create a hotfix branch from the latest release tag. When the hotfix is ready, we deploy it, tag it and merge the branch to main.

## Release strategy

All work is organised and synchronised in 7 week cycles, each of which consist of three 2-week sprints and a reflection week. We use release trains, set against this schedule to plan releases into the future.

Each release is versioned using cycle, sprint and hotfix numbers:

```
{cycle}.{sprint}.{hotfix}

The major version grows by one after every 7 week cycle.
The minor version grows by one for every sprint of a cycle, then resets.
The patch version grows by one for every hotfix after a major/minor release.
```

Sprints generally start on Mondays and end with a demo a week later on Friday.

* On the Monday after the first sprint of the first cycle, we release version 0.1.0.
* If we release a hotfix for 0.1.0, it gets the version 0.1.1.
* On the Monday after the second sprint of the first cycle, we release version 0.2.0.
* On the Monday after the third and final sprint of the first cycle, we release version 1.0.0, since that's the end of the cycle.
* After the reflection week, a new cycle starts.
* On the Monday after the first week of the second cycle, we release version 1.1.0.

To catch a release train, you need to finish your feature and get it approved and merged to main before the train departs. Larger features usually launch on a cycle (major) release. Smaller features can launch on a sprint (minor) release.

Before a release goes into production, it gets deployed to a pre-production environment. Each team has a release manager that reviews and signs off on the changes.

### Continuous Delivery

We have the following deployment environments:

* feature branches: Manually deployed to a sandbox environment.
* main: Automatically deployed to the development environment, with dev data and all feature flags turned on.
* main: Automatically deployed to the staging environment, with some production data and all feature flags turned on.
* release and hotfix branches: Automatically deployed to the pre-production environment, with production data and all feature flags turned off.
* release tags: Manually deployed to production.


# Project Management

## Development process

We work according to Agile and DevOps methodologies, where we focus on releasing small features frequently so we can get customer feedback early in the process. Our entire release cycle is automated which shortens release time so we can develop and respond quickly. We deploy to three environments: Dev, Staging and Prod. Releases to the Dev environment uses continuous deployment where we have a set of fake data that can be used for testing.

Release to production happens on a shared schedule which sets the tempo and rhythm for all projects across all teams. Each development cycle is 7 weeks in total and consists of three, two week sprints and one refactor week. Deployments are scheduled after each sprint along with demos where new features and changes are demonstrated for all interested parties.

Everything about our Continuous Delivery process can be found here: [Continuous Delivery](/development/devops/continuous-delivery)

## Quality gates

We ensure software quality in many aspects. Here are some highlights:

* Automatic tests are required in our projects. [More information](https://docs.devland.is/repository/system-e2e).
* All code is owned by some team which reviews all changes to the code they are responsible for. All code must be reviewed by at least one separate person. [More information](https://docs.devland.is/technical-overview/code-reviews).
* We have a robust operational monitoring system which allows us to react to incidences quickly. [More information](https://docs.devland.is/technical-overview/devops/observability#provide-observability-into-the-applications).
* We use feature flagging technology that allowes us to get features to production in dormant state and then activated later. This way we get smaller features through the development process and can test certain functionality on limited user groups. [More information](https://docs.devland.is/technical-overview/feature-flags).

## Definition of done

Before we release features to the general public we review the following list and make sure that all appropriate items have been addressed:

* **Architecture:** has been reviewed by the Core and DevOps team.
* **Language support:** user-facing products are available in both Icelandic and English.
* **Accessibility:** UI and UX is according to our accessibility policy.
* **Testing:**
  * Test cases have been reviewed by the Product Owner.
  * External integration tests have been created when we depend on third party APIs.
  * Internal API tests and unit tests have been created.
  * End to end tests have been created for smoke tests.
* **Audit logs:** all user interactions/changes are audit logged.
* **Security:** review if new API functionality is correctly authorized and protected.
* **Technical documentation:** technical documentation has been added in the context of the feature.
* **Logging implemented:** logging is sufficient so that the solution can be monitored. [More information](https://docs.devland.is/technical-overview/devops/logging).
* **Analytics:** anonymous usage monitoring of new features has been set up.
* **Organization approval:** if the feature is a collaboration with another organization they should approve the release.
* **External APIs:** when using a new web service from another organization, verify that it is correctly configured and reachable in production.
* **Delegations:** check if new functionality should be available when a user acts on behalf of a company, their child, or another person.

For digital applications we add the following items to our Definition of Done.

* **States:** are application states correctly configured for the application overview screen.
* **Data collection:** the data collection screen should be approved by the organization and Stafrænt Ísland.
* **Roles:** if multiple parties contribute to the same application, then review the roles and make sure they can only access the correct data.
* **Lifecycle:** how long we store application data should be reviewed and approved by the organization.
* **Payments:** when using ARK-Quickpay, we need to sync with FJS on making the product ID available in QuickPay and make sure that payments are confirmed.
* **Article:** when an article that points to a new digital application has been published in the CMS, it should be tagged with the tag ‘umsokn’. This enables front ends, e.g. the Ísland.is app, to list it with other fully digital applications.

After release:

* **Feature flagging:** When the feature has been deployed to the general public, we need to clean up the feature flag and remove all code which the feature flag replaced. [More information](https://docs.devland.is/technical-overview/feature-flags).


# Teamwork

Projects are developed in teams that win tender contracts with Digital Iceland. These teams come from different companies, but work in the same codebase and projects. So it is important to foster good communications and collaboration as well as to formalise responsibilities and decision-making.

The first step is to get everyone in the same room, be it online or offline. We use Slack to host discussions in multiple focused channels. This gives everyone the chance to ask questions and get feedback on what they're working on.

## Disciplines

Disciplines connect teams to discuss issues, share knowledge and make decisions.

Each discipline has a discipline manager that organises regular discipline meetings, manages agendas and publishes meeting minutes and decisions. During a discipline meeting, it's the manager's role to keep discussions productive and decide if something needs further research or a vote.

Meetings are open to interested parties but should be attended by at least one person from each active team that are part of the discipline. Discipline members can submit items to the agenda. Each item on the agenda should have an owner that presents the item and any proposals for discussion.

Discipline meetings should be used to get decisions on smaller issues and communicate best practices across teams. Larger issues and discussions should be moved to RFCs. The goal is to discuss, decide and move along.

Currently there are 3 disciplines, but this may change as needed at any time.

### Dev

Responsible for the monorepo, dependencies, tooling and shared code.

### Devops

Responsible for CI, CD, operations and monitoring.

### Design

Responsible for the brand, design system, UX and consistent design across projects.

## Architecture decision record

It is important to document all important decisions made in this project. This might, for instance, be a technology choice (e.g., PostgreSQL vs. MongoDB), a choice between a library (e.g., moment vs date-fns), or a decision on features (e.g., pagination vs infinite scroll). Design documentation is important to enable people understanding the decisions later on.

Decisions should be documented using [MADR](https://github.com/adr/madr) formatting inside the `adr` folder. Just copy `0000-template.md` to for example `0001-date-library.md` and fill in the details. Many sections can be skipped for smaller decisions.


# Architectural Decision Records

This log lists the architectural decisions for island.is.

For new ADRs, please use [template.md](/technical-overview/adr/template) as basis. More information on MADR is available at <https://adr.github.io/madr/>. General information about architectural decision records is available at <https://adr.github.io/>.

## Content

* [ADR-0000](/technical-overview/adr/0000-use-markdown-architectural-decision-records) - Use Markdown Architectural Decision Records
* [ADR-0001](/technical-overview/adr/0001-use-nx) - Use NX
* [ADR-0002](/technical-overview/adr/0002-continuous-integration) - Continuous Integration
* [ADR-0003](/technical-overview/adr/0003-css) - CSS
* [ADR-0004](/technical-overview/adr/0004-branching-and-release-strategy) - Branching and release strategy
* [ADR-0005](/technical-overview/adr/0005-error-tracking-and-monitoring) - Error tracking and monitoring
* [ADR-0006](/technical-overview/adr/0006-what-api-management-tool-to-consider) - What API Management tool to consider
* [ADR-0007](/technical-overview/adr/0007-viskuausan-static-site-generator) - Viskuausan Static Site Generator
* [ADR-0008](/technical-overview/adr/0008-use-oauth-and-openid-connect) - Use OAuth 2.0 and OpenID Connect as protocols for Authentication and Authorization
* [ADR-0009](/technical-overview/adr/0009-naming-files-and-directories) - Unified naming strategy for files and directories
* [ADR-0010](/technical-overview/adr/0010-cms) - CMS
* [ADR-0011](/technical-overview/adr/0011-open-source-license) - Open source license
* [ADR-0012](/technical-overview/adr/0012-chart-library) - Chart library
* [ADR-0013](/technical-overview/adr/0013-feature-flags) - What Feature Flag Service/application Should We Use at Island.is?
* [ADR-0014](/technical-overview/adr/0014-logging-apm-monitoring) - Logging, monitoring and APM platform
* [ADR-0015](/technical-overview/adr/running-maestro-mobile-e2e-tests-in-ci) - Running Maestro mobile E2E tests in CI


# Use Markdown Architectural Decision Records

* Status: accepted
* Deciders: devs, devops
* Date: 01.06.2020

## Context and Problem Statement

We want to record architectural decisions made in this project. Which format and structure should these records follow?

## Considered Options

* [MADR](https://adr.github.io/madr/) 2.1.0 - The Markdown Architectural Decision Records
* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) - The first incarnation of the term "ADR"
* [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) - The Y-Statements
* Other templates listed at <https://github.com/joelparkerhenderson/architecture_decision_record>
* Formless - No conventions for file format and structure

## Decision Outcome

Chosen option: "MADR 2.1.0", because

* Implicit assumptions should be made explicit.

  Design documentation is important to enable people understanding the decisions later on.

  See also [A rational design process: How and why to fake it](https://doi.org/10.1109/TSE.1986.6312940).
* The MADR format is lean and fits our development style.
* The MADR structure is comprehensible and facilitates usage & maintenance.
* The MADR project is vivid.
* Version 2.1.0 is the latest one available when starting to document ADRs.


# Use NX

* Status: accepted
* Deciders: devs
* Date: 03.05.2020

## Context and Problem Statement

We want a monorepo tool to help us to scale development up for multiple projects and teams. It should not be too much in the way, but help us manage code, dependencies and CI/CD.

## Decision Drivers

* Low complexity and overhead in development.
* Fit for our stack.
* Optimize CI/CD with dependency graphs and/or caching.
* Flexible.

## Considered Options

* [Bazel](https://bazel.build/)
* [Nx](https://nx.dev/)
* [Lerna](https://lerna.js.org/)

## Decision Outcome

Chosen option: "Nx", because:

* It's specially designed around our stack (TypeScript, React, Node.JS, NPM, ESLint, Prettier, Cypress, Jest, NextJS).
* It's relatively easy to learn with focused documentation.
* It has schematics to generate apps, libraries and components that includes all of our tools.
* It is opinionated, which gives us a good base to start developing faster. Many things can still be configured or extended.

## Pros and Cons of the Options

### [Bazel](https://bazel.build/)

* Good, because it's created and maintained by Google
* Good, because it supports multiple programming languages and platforms.
* Bad, because it's difficult to learn, with a custom BUILD files.
* Bad, because JS support is hacky.

### [Nx](https://nx.dev/)

* Good, because it has built in support for our stack.
* Good, because it's been around for a while, originating in the Angular world.
* Good, because it's designed with best practices for large scale web applications.
* Good, because it supports elaborate code generation.
* Good, because it helps optimise CI/CD for large projects.
* Bad, because it's fairly opinionated.
* Bad, because it's an open source project maintained by an agency.

### [Lerna](https://lerna.js.org/)

* Good, because it integrates with NPM and Yarn.
* Good, because it's used by a lot of open source projects.
* Bad, because it's primarily designed for managing and publishing open source projects, not building and deploying large scale applications.

## Links

* [Why you should switch from Lerna to Nx](https://blog.nrwl.io/why-you-should-switch-from-lerna-to-nx-463bcaf6821)


# Continuous Integration

* Status: accepted
* Deciders: devs, devops
* Date: 25.05.2020

## Context and Problem Statement

We need to maintain the quality of the codebase, minimize the time between introducing quality degradation and discovering it and make sure we have deployable artefacts at all times. In the context of a [monorepo](/technical-overview/monorepo) we need to do this efficiently in order to make this process scale for an ever-growing number of projects in the repository.

### Terms

* `code integration` - this is a process that checks the integrity/quality of the code - static code analysis, code formatting, compilation, running automated tests, etc. The process is usually in the form of one or more scripts and uses tools local to the repository with minimum external dependencies.
* `artefact building` - this is a process that packages artefacts, labels them and usually publishes them to a central artefact repository so that they can be used by the deployment process. This process makes sense to be executed only after `code integration` process finishes successfully.
* `continuous integration` - the practice of running the `code integration process` triggered by events such as

  * pushing new revisions of the code to the code repository
  * opening a Pull Request
  * fixed schedule
  * etc.

  We also run the `artefact building` process after a successful `code integration` process to have artefacts ready for deployment at all times.
* `continuous integration platform` (CI platform from here on) - it is a platform (self-hosted or SaaS) that provides integrations to make it easy to run your `continuous integration` and publish the results

## Decision Drivers (Policy)

* The code integration process needs to be independent from CI platform integration
  * Benefits
    * Easier troubleshooting and development of the process
    * Easier migration to a different CI platform
    * Easier experimentation
    * Easier to run as part of the development process
  * Drawbacks
    * Needs more knowledge and experience
* We use Docker as much as possible to implement the steps in the integration process
  * Benefits
    * Platform independence
    * Repeatability
    * Security
  * Drawbacks:
    * Needs expertise in Dockerfile and Docker in general
* We only build the code affected by the change but re-tag all unchanged code artefacts
  * Benefits
    * Be able to release a consistent version of all necessary services. The Docker images for all services in the monorepo should have the same Docker image tag available for a commit hash
    * Supports the monorepo benefits and ideology
  * Drawbacks
    * Can be tricky, especially for artefacts that are not Docker images(currently we do not plan to have those)
* We support only Linux as a target operating system when we cannot use Docker
  * Benefits
    * Same as the OS we use in our production environment, which minimizes the chances of failure because of OS differences
    * We minimize the effort and complexity of supporting different operating systems
    * Linux tooling works on all major other OSs today - macOS and Windows
  * Drawbacks:
    * Devs that use non-Linux OS might need to install additional software and customizations

## CI Platform Considered Options

We only considered hosted solutions at this time to minimize the number of systems we need to maintain. Migrating to a different platform should not be a big or risky endeavour. They are merely convenient integrations with the code repository, cache hosting and notifications.

* GitHub Actions
  * Benefits
    * Well integrated with our code which is in GitHub
    * Due to the integration we do not need to provide
    * Well documented
    * Supports self-hosted runners
    * Well priced (free, not sure if there is a limit)
  * Drawbacks
    * Relatively new
* Circle CI
  * Benefits
    * Mature
    * Well-known
    * Supports self-hosted runners
    * Not sure if parallelization is supported on open-source projects
  * Drawbacks
    * It will cost us (they have a free tier but with a limit which seems we will likely reach)
* AWS CodeBuild
  * Benefits
    * Scalable builds
    * Best security model when part of our AWS account structure
    * Reasonably priced?
  * Drawbacks
    * UI is kind of bad

## Decision Outcome

GitHub Actions

* Number 1 CI platform on GitHub at the time of this writing
* Easy customization of which parts of the CI process to run depending on branching patterns and pull requests
* Good integration of code health with the pull request process
* As a GitHub open-source project, we have an unlimited number of "compute"-minutes that come as a part of the package
* Supports parallelisation of the process which can be pretty important in the context of monorepo
* Support using own runners which can be helpful to maximize speed, minimize costs and increase security.


# CSS

* Status: accepted
* Deciders: devs
* Date: 2020-05-26

## Context and Problem Statement

We're building websites and web applications that share a common design system with reusable components. How do we write CSS styles in a way that is performant and safe?

## Decision Drivers

* Should be performant, with code splitting, caching and minimal runtime overhead.
* Needs to have easy access to our design system constants. These should optimally be shared with JS logic.
* Should be type-safe to catch issues when refactoring.
* Reusable components should be closed, not accepting arbitrary styles/classes.
* We want a pattern for responsive props with atomic layout components.

## Considered Options

* [CSS Modules](https://github.com/css-modules/css-modules) with [SASS](https://sass-lang.com/)/[PostCSS](https://postcss.org/)
* [Styled Components](https://styled-components.com/)
* [Treat](https://seek-oss.github.io/treat/)

## Decision Outcome

Chosen option: Treat, because it combines the best of both worlds from CSS-in-JS and CSS modules.

We'll create shared components that have responsive props, but are otherwise closed for modifications. Theme variables are defined in a shared library with TypeScript.

Example:

```typescript
// Good:
<Box padding"small" />
<Box padding={{xs: 'small', md: 'medium'}} />
<Input large />
<Text preset="heading3" as="p" />
```

```typescript
// Bad:
<Box className={customLayout} />
<Input style={{ height: 50, padding: 16 }} />
<Text className={styles.heading} />
```

### Positive Consequences

* Treat is statically extracted at build time, so it has minimal runtime.
* Styles load in parallel with JS, also when code splitting.
* Styles are written in TypeScript which gives us type safety when referring to shared variables, styles and helpers.
* Styles are in special files, separate from markup and components giving us clear separation with good visibility into the rendered markup.
* We can pull in responsive layout component patterns from Braid, which gives us a good base to lay out components and pages.

### Negative Consequences

* We are choosing a pretty new framework, so it may 1) have bugs or issues, 2) be an obstacle for new developers or 3) be discontinued.
* When we're generating responsive styles at build time we need to be mindful at how many variations we allow (eg media queries, columns, whitespace), since they can easily bloat our CSS with unused styles.

## Pros and Cons of other Options

### CSS Modules with SASS/PostCSS

* Good, because it builds on top of standard CSS syntax which everyone knows.
* Good, because it has no runtime.
* Good, because it is separate from markup.
* Bad, because it is messy to generate advanced styles in a CSS-based language.
* Bad, because it's not type safe.

### Styled Components

* Good, because it's the industry leader in CSS-in-JS.
* Good, because it allows rendering pages with no redundant styles.
* Good, because it has excellent developer experience, making it easy to implement dynamic styles based on theme/props.
* Bad, because it's runtime may significantly affect site performance.
* Bad, because it hides the markup which may cause accessibility issues.


# Branching and Release Strategy

* Status: accepted
* Deciders: devs, devops
* Date: 2020-05-24

## Context and Problem Statement

How do we want to organise work in branches and how should changes be released? How should different branches be continuously deployed for QA?

## Decision Drivers

* We need to have confidence in our releases.
* We want more structured releases while we're still getting our footing in a shared monorepo.
* We need simplicity and clear [takt time](https://kanbanize.com/continuous-flow/takt-time) so different teams can plan for what is going out the door from them.
* It should work well with our agile work environment.

## Considered Options

Branching strategies:

* [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/)
* [GitHub Flow](https://guides.github.com/introduction/flow/)
* [OneFlow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow)

Release strategies:

* [Continuous delivery](https://martinfowler.com/bliki/ContinuousDelivery.html)
* [Release trains](https://martinfowler.com/articles/branching-patterns.html#release-train)

## Decision Outcome

Chosen option: "OneFlow" because it provides a single eternal branch with well structured releases.

We'll implement OneFlow with these details:

* Release branches are set up the Monday after each sprint. This is sometimes called release trains, where features line up for different release trains.
* Release and quality managers from each team are responsible for reviewing and approving releases.
* Releases apply to all apps in the monorepo.
* Releases are versioned like this: `{cycle}.{sprint}.{hotfix}`. So version 3.1.2 is the release after cycle 3, sprint 1 with two hot fixes applied.
* Feature branches are merged using "Squash and merge", so they can be easily reverted.
* There are two ways to build larger features.
  * If the feature is isolated and not likely to cause conflicts, they can stay on long-living feature branches until they are ready to be released.
  * If the feature touches many parts of the codebase, it can be useful to merge changes more often but hide the feature in production with feature flags.
* If a project needs to deploy updates outside of the sprint rhythm, they should use hotfix branches.

### Future strategy

With time, we expect to build up better testing capabilities which gives us more confidence in the health of our monorepo. Then we can move quicker, with a simpler GitHub Flow branching strategy and continuous delivery into production.

### Hosting environments

We'll set up continuous delivery to different hosting environments:

| Environment | Git source            | Databases/services | Features |
| ----------- | --------------------- | ------------------ | -------- |
| sandbox     | feature branch        | Test               | All      |
| dev         | main                  | Test               | All      |
| staging     | main                  | Prod               | All      |
| pre-prod    | release/hotfix branch | Prod               | Finished |
| prod        | latest release tag    | Prod               | Finished |

We'll probably start with dev, staging, pre-prod and prod environments, since feature branch deployments are more dynamic and difficult to manage.

## Pros and Cons of Branching Options

### Git Flow

* Good, when there needs to be multiple versions in production.
* Good, because it enforces an easy to comprehend naming convention for branches.
* Good, because it has good support in popular git tools.
* Bad, because the git history becomes unreadable.
* Bad, because the main/develop split is redundant.

### GitHub Flow

* Good, because it fits well with Continuous Delivery and Continuous Integration.
* Good, a simpler alternative to Git Flow.
* Good, when we need to maintain a single version in production.
* Bad, because production code can become unstable most easily.
* Bad, if we need release plans.

### One Flow

* Good, because it has a clean git history (with squash-and-merge).
* Good, because it has a structured release process without multiple long running branches.
* Good, because it has good parts from GitHub Flow (simple history with one branch + feature branches) and Git Flow (releases and hot fixes).
* Bad, because it makes continuous integration more difficult.

## Pros and Cons of Release Options

### Continuous Delivery

* Good, because it is simpler and leaner, allowing changes to be deployed quicker.
* Bad, because it can easily break something in production if our CI isn't good enough.

### Release trains

* Good, because it has more structured releases, which helps with planning and QA.
* Good, because it can be synchronised to organisational schedule.
* Good, because it gives us a process to verify and test each release.
* Bad, because it is fairly rigid and complicated to implement organisation-wide.

## Links

* [4 branching workflows for Git](https://medium.com/@patrickporto/4-branching-workflows-for-git-30d0aaee7bf)
* [Branching patterns - Martin Fowler](https://martinfowler.com/articles/branching-patterns.html)


# Error Tracking and Monitoring

* Status: accepted
* Deciders: devs, devops
* Date: 12.06.2020

## Context and Problem Statement

Know it before they do! We need a tool to discover, triage, and prioritize errors in real-time.

## Considered Options

* [Bugsnag](https://www.bugsnag.com/)
* [Sentry](https://sentry.io/)

## Decision Outcome

Chosen option: `Sentry`, because it ranks higher in a community survey regarding our stack (Javascript). It's also much cheaper and offers the choice to be completely free if we self-host it.

## Pros and Cons of the Options

### Bugsnag

* Good, because it offers a Slack integration for faster feedback.
* Good, because it offers a Github integration to link to possible commits and PRs.
* Good, because it offers bot front-side/server-side/serverless error tracking.
* OK, because it was ranked the **#5** as the best Javascript (client-side) error logging service in a community survey.
* Bad, because it's expensive. (**$199/mo** for **450k events** and **15 collaborators**)
* Bad, because it's pricing includes a fixed set of collaborators.

### Sentry

* Good, because it offers a Slack integration for faster feedback.
* Good, because it offers a Github integration to link to possible commits and PRs.
* Good, because it offers bot front-side/server-side/serverless error tracking.
* Good, because it was ranked the **#1** as the best Javascript (client-side) error logging service in a community survey.
* Good, because it's cheaper than most error logging services out there (half the price of Bugsnag).
* Good, because it offers the possibility of being completely free with a self-hosted solution (since Sentry is open-source).
* Good, because you only pay for the number of events, regardless of how many collaborators.
* Bad, because it costs (since we won't go with the self-hosted solution at first). (**$89/mo** for **500k events** and **∞ collaborators**)


# What API Management Tool to Consider

* Status: accepted
* Deciders: devs
* Date: 2020-09-14

Technical Story: Design of Api Gateway / API Portal

## Context and Problem Statement

Is there available tool that is compliant to requirements? Can the tool provide functionality for API Gateway? Can the tool provide functionality for API Development Portal?

### Requirements

Since the API Gateway is intended for students and startups to gather open government data, the following requirements need to be fulfilled. The student / startup is defined as Consumer of service. The organization that deliver the service as open service is defined as Provider of service. The open service is hosted on organizations X-Road server. The API Gateway must provide functionality for

* Registration of services with rate limit
* Self-service portal
* API key for Consumer
* Rate limit for Consumer

#### Provider

* Register open service in API gateway.
* Set rate limit on open service in API gateway.

#### Consumer

* Register as service user.
* Register application intended to use API (Consideration).
* Get API key for that application or consumer.
* Register what API to use in the application.
* Ability to test the API from API console with application API key (Consideration).

#### Considerations

API Keys / Rate Limits Is it sufficient to have only One API key for each Consumer, or is it required to define different Consumer applications with different API key. If a typical Consumer has created application and has valid API key, it is likely that he will not bother to register new application and get new API key. He could reuse the already given one. Consumer could also use the ability to register another application and get new API key with fresh rate limits.

Consumer registration What will be used to validate / approve students or startups for access on services. Should it be registered by SSN or some unique id, or only by email, with ability to reregister with new email again and again.

## Decision Drivers

* Vendor lock in for runtime
* Open source or not
* Installation options
* Functional ability
* Market presence
* Pricing

Pricing model for API management solutions are complex. Usually based on transaction count, or CPU instances. Sometimes pricing is variation of annual fee and transactional fee. All prices that are exposed in this documentation are estimates, needed to be negotiated with vendor.

There is consideration that most API management providers are aiming customers in hosted solutions, instead of on-prem installation, that would provide lock in for that vendor.

### Functional ability for decision

Functional ability to consider when evaluating the tool. The following list was taken from [wikipedia page for API Management](https://en.wikipedia.org/wiki/API_management).

* Gateway: a server that acts as an API front-end, receives API requests, enforces throttling and security policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to support authentication, authorization, security, audit and regulatory compliance.
* Publishing tools: a collection of tools that API providers use to define APIs, for instance using the OpenAPI or RAML specifications, generate API documentation, manage access and usage policies for APIs, test and debug the execution of API, including security testing and automated generation of tests and test suites, deploy APIs into production, staging, and quality assurance environments, and coordinate the overall API lifecycle.
* Developer portal/API store: community site, typically branded by an API provider, that can encapsulate for API users in a single convenient source information and functionality including documentation, tutorials, sample code, software development kits, an interactive API console and sandbox to trial APIs, the ability to subscribe to the APIs and manage subscription keys such as OAuth2 Client ID and Client Secret, and obtain support from the API provider and user and community.
* Reporting and analytics: functionality to monitor API usage and load (overall hits, completed transactions, number of data objects returned, amount of compute time and other internal resources consumed, volume of data transferred). This can include real-time monitoring of the API with alerts being raised directly or via a higher-level network management system, for instance, if the load on an API has become too great, as well as functionality to analyze historical data, such as transaction logs, to detect usage trends. Functionality can also be provided to create synthetic transactions that can be used to test the performance and behavior of API endpoints. The information gathered by the reporting and analytics functionality can be used by the API provider to optimize the API offering within an organization's overall continuous improvement process and for defining software Service-Level Agreements for APIs.
* Monetization: functionality to support charging for access to commercial APIs. This functionality can include support for setting up pricing rules, based on usage, load and functionality, issuing invoices and collecting payments including multiple types of credit card payments.

## Considered Options

* [Google Apigee Edge](https://cloud.google.com/apigee/api-management)
* [Mulesoft Anypoint](https://www.mulesoft.com/platform/api-management)
* [Software AG API Management](https://softwareaggov.com/products/integration/webmethods-api-management/)
* [IBM API Connect](https://www.ibm.com/cloud/api-connect)
* [Axway Ampify](https://www.axway.com/en/products/api-management)
* [Tibco Mashery](https://www.tibco.com/products/api-management)
* [AWS](https://aws.amazon.com/api-gateway/api-management/)
* [Akana](https://www.akana.com/)
* [Sensedia](https://sensedia.com/)
* [Kong](https://konghq.com/)
* [Red Hat 3Scale](https://www.3scale.net/)
* [WSO2](https://wso2.com/api-management/)
* [Tyk](https://tyk.io/)
* [Dell Boomi](https://boomi.com/)
* [Microsoft Azure API Management](https://azure.microsoft.com/en-us/services/api-management/)
* [Nginx Plus](https://www.nginx.com/)
* [Broadcom Layer7](https://www.broadcom.com/products/software/api-management)
* [KrakenD](https://www.krakend.io/)
* [Netflix Zool](https://github.com/Netflix/zuul)
* [Api Umbrella](https://apiumbrella.io/)
* [Express Gateway](https://www.express-gateway.io/)
* [Gravitee.io](https://gravitee.io/)

### Considered options functional matrix

The following list checks out the options. The options were checked by looking into documentation and read reviews. A Gap in the matrix does not mean that the option does not exist, only that it was not noted in documentation.

| API Management Tools                                 | Apigee Edge | Mulesoft Anypoint | Software AG | IBM | Axway | Tibco Mashery | AWS  | Akana | Sensedia | Kong | Red Hat 3Scale | WSO2        | Tyk          | Boomi | Azure | Nginx Plus | Broadcom | KrakenD | Netflix Zool | API Umbrella | Express Gateway | Gravitee.io    |
| ---------------------------------------------------- | ----------- | ----------------- | ----------- | --- | ----- | ------------- | ---- | ----- | -------- | ---- | -------------- | ----------- | ------------ | ----- | ----- | ---------- | -------- | ------- | ------------ | ------------ | --------------- | -------------- |
| **Platform Information**                             |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| On premise installation                              | Yes         | Yes               | Yes         | Yes | Yes   | Yes           |      | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      | Yes     | Yes          | Yes          | Yes             | Yes            |
| Cloud Service                                        | Yes         | Yes               | Yes         | Yes | Yes   | Yes           | Yes  |       |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   |            | Yes      |         |              |              |                 |                |
| Hybrid Installation                                  | Yes         | Yes               | Yes         |     |       | Yes           |      |       |          |      |                |             |              |       |       |            | Yes      |         |              |              |                 |                |
| Open Source                                          | No          | Yes/No            | No          |     | No    | No            | No   | No    | No       | Yes  | Yes            | Yes         | Yes          | No    | No    | No         | No       | Yes     | Yes          | Yes          | Yes             | Yes            |
| License model                                        | Paid        | Paid              | Paid        |     | Paid  | Paid          | Paid | Paid  | Paid     | Paid | Apache/Paid    | Apache/Paid | Mozilla/Paid | Paid  | Paid  | Paid       | Paid     | Apache  | Apache       | MIT          | Apache License  | Apache License |
| Cost of usage (on prem)                              |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| Cost of usage (cloud)                                |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| Gartner 2019                                         | #1          | #2                | #3          | #4  | #5    | #6            | #12  |       | #9       | #7   | #8             | #10         | #17          | #20   | #14   | N/A        | #13      | N/A     | N/A          | N/A          | N/A             | N/A            |
| Forrester 2020                                       | #3          | #6                | #1          | #2  | #5    | #6            |      | #5    |          | #14  | #11            | #4          | #12          | N/A   | #13   | N/A        | N/A      | N/A     | N/A          | N/A          | N/A             | N/A            |
| Forrester 2018                                       | #2          | #10               | #3          | #1  | #7    | #6            |      | #4    |          |      | #15            | #5          | #12          | N/A   | #12   | N/A        | N/A      | N/A     | N/A          | N/A          | N/A             | N/A            |
| Forrester Market precense 2020                       | 1           | 1                 | 2           | 1   | 3     | 2             |      | 4     | 5        |      | 3              | 3           | 5            | N/A   | 2     | N/A        | N/A      | N/A     | N/A          | N/A          | N/A             | N/A            |
| Forrester Market precense 2018                       | 1           | 1                 | 3           | 2   | 3     | 3             |      | 5     | 5        |      | 3              | 3           | 5            | N/A   | 2     | N/A        | N/A      | N/A     | N/A          | N/A          | N/A             | N/A            |
|                                                      |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| **Gateway**                                          |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| Oauth                                                | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      | Yes     |              | Yes          | Yes             | Yes            |
| OpenID Connect                                       | Yes         | Yes               | Yes         |     | Yes   |               | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      |         |              |              |                 | Yes            |
| Caching                                              | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      | Yes     |              |              |                 | Yes            |
| Throttling / Rate limit                              | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      |         | No           | Yes          | Yes             | Yes            |
| Analytics                                            | Yes         | ?                 | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   | Yes        |          | No      |              |              |                 |                |
| Stages (prod/dev/test)                               | Yes         | Yes               | Yes         |     |       | Yes           | Yes  |       |          |      | Yes            | Yes         |              | Yes   | Yes   | Yes        |          |         |              |              |                 |                |
|                                                      |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| **Publishing Tool**                                  | Yes         | Yes               | Yes         |     |       |               |      |       |          |      |                | Yes         |              |       |       |            |          | No      |              |              |                 |                |
| OpenAPI Description                                  | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   | Yes   |            | Yes      |         |              |              | No              | Yes            |
| RAML API Descriptor                                  |             | Yes               |             |     | Yes   | Yes           |      | Yes   |          |      | Yes            |             |              | Yes   | No    |            |          |         |              |              |                 |                |
| Soap WSDL Description                                | Yes         | Yes               | Yes         |     | Yes   | Yes           |      |       |          |      | Yes            | Yes         | Yes          | Yes   | Yes   |            | Yes      |         |              |              |                 |                |
| Does tool provide Life Cycle Management of Services. | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          |      |                | Yes         |              |       | Yes   |            |          |         |              |              |                 | Yes            |
| Message Mediation / Orchestration / Transformations  | Yes         |                   | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  |                | Yes         | Yes          | Yes   | Yes   |            | Yes      |         |              |              |                 | Yes            |
| Does tool provide Dynamic endpoints.                 | Yes         |                   | Yes         |     | Yes   | Yes           |      |       |          | Yes  |                | Yes         | Yes          |       |       |            |          |         |              |              |                 |                |
| API Interface for registration of services           | Yes         |                   |             |     | Yes   |               | Yes  | Yes   |          | Yes  |                | Yes         | Yes\*        |       |       |            |          |         |              |              |                 |                |
|                                                      |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| **Developer portal/API store**                       |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          | No      | No           |              | No              |                |
| API Inventory                                        | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  | Yes   |          | Yes  | Yes            | Yes         | Yes          | Yes   |       | Yes        | Yes      |         |              | Yes          |                 | Yes            |
| Access request workflow                              | Yes         | Yes               | Yes         |     | Yes   |               |      |       |          |      |                | Yes         | Yes          |       |       |            | Yes      |         |              |              |                 | Yes            |
| Branding / Customize user interface                  | Yes         | Yes               | Yes         |     |       | Yes           | Yes  |       |          | Yes  | Yes            | Yes         | Yes          | Yes   |       |            | Yes      |         |              |              |                 |                |
| Analytics                                            |             |                   |             |     |       |               |      |       |          |      |                | Yes         |              | Yes   |       |            |          |         |              |              |                 | Yes            |
|                                                      |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          |         |              |              |                 |                |
| **Reporting and analytics**                          |             |                   |             |     |       |               |      |       |          |      |                |             |              |       |       |            |          | No      | No           |              | No              |                |
| Does tool provide Monitoring Dashboard               | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  |       |          | Yes  |                | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      |         |              |              |                 | No             |
| Does tool provide Logging of request.                | Yes         | Yes               | Yes         |     | Yes   | Yes           | Yes  |       |          | Yes  |                | Yes         | Yes          | Yes   | Yes   | Yes        | Yes      |         |              |              |                 |                |
| Does tool provide statistics for SLA.                | Yes         | Yes               | Yes         |     | Yes   |               | Yes  |       |          |      |                | Yes         |              |       |       |            |          |         |              |              |                 |                |
| Does tool provide logging to ELK / 3rd party logging | Yes         | Yes               | Yes         |     | Yes   | Yes           |      |       |          | Yes  |                | Yes         | Yes          |       |       | Yes        | Yes      |         |              | Yes          |                 | Yes            |

## Decision Outcome

We recommend using hosted solution from **AWS** for API gateway. The reason is that if we look at the requirements and other architectural decisions in the project, the AWS solution does both fit in the architecture and pricing based on usage is cheaper than in other options. We made a pricing estimate for five years. Based on 100 million API calls per month the price of using AWS is one third of bought enterprise or homemade solutions. If the usage is 20 million API calls per month, we are looking at one fifth of the enterprise solutions. Note that there is also cost in using the management API and storage cost of logging, but it seems to be fraction of the total cost of using the product. Since the requirement is to host X-Road services that are defined as open and hosted at organization, we need to access the service through open X-Road server. Currently there will be installed X-Road server on AWS environment to use by island.is, that server can also be used by API gateway. Downside is that all request needs to go to the AWS environment, and then go back to Iceland. According to vendor lock in, then the investment cost of this option is not in the range that it will stop us to change to other solution. That could happen if requirement changes or the usage will be more than expected. This decision is based on the requirements and intended usage. If those requirements change, for example we would use the API portal as portal for Viskuausan, or more intense usage is expected, other options could be more relevant.

Following is the decision phases used to get this conclusion.

### Second phase of decision

For Open Source tool, we recommend usage of **Kong Community Edition**, with custom made API Developer Portal and Analytics. The analytics part could be based on ELK stack through plugin. The Kong community is large, and there are some Developers Portals available in the Open Source community. There is also some plugin available for logging and monitoring available. Kong API Gateway provides rest interface that can be used for customizing API Portal, and ability to create custom plugins for custom implementations. This decision provides more custom code to be developed and we need to rely on that the community can provide plugins. We also rely on that the Kong product will remain open source, but lot of plugins are only available for Enterprise edition.

**WSO2** could be considered, since the whole suite is Open Source, so API Developer Portal and Admin UI is part of their Open Source offering. It is not recommend to use it without paid support plan.

For Vendor specific tool we recommend **Software AG API Management**. It is fully functional with customizable Developer Portal, and analysis tool. It has both partner and customers in Iceland. Current pricing model is based on transaction count and same applies for On-Prem vs. Hosted implementations. There are no cloud provider or runtime lock in. Implementation is that the tool needs to be installed and configured. The Developer Portal needs to be customized. For starter it is also option to host the installation at Advania for further evaluation. Analytics are fully integrated to ELK stack.

For hosted solutions, we recommend **AWS**, since it best fits the architectural decisions made for island.is

### First phase of decision

In the first decision phase the following tools were initially pinpointed for further analysis. That was based on the option to run the API Management tool on premise. In decision outcome above, the tools have been narrowed to two options.

If open source options are not a requirement, it is suggested to evaluate the following tools.

* [Software AG API Management](https://softwareaggov.com/products/integration/webmethods-api-management/)
* [IBM API Connect](https://www.ibm.com/cloud/api-connect)
* [Google Apigee Edge](https://apigee.com/about/cp/open-source-api-management)
* [Mulesoft Anypoint](https://www.mulesoft.com/platform/api-management)
* [Axway Ampify](https://www.axway.com/en/products/api-management)

These are the tools that are most mature, and do not provide lock in for runtime platform. They need to be evaluated based on pricing and technical ability.

If true open source is required, it is suggested to evaluate the following tools.

* [WSO2](https://wso2.com/api-management/)
* [Kong](https://konghq.com/)

These tools provide open source offering, but in most cases the features for Api Developer Portal and Publishing tools are only part of enterprise offering with subscription. Evaluation is needed for validating if the open source offering of the tool contains what is needed for implementation. We need to evaluate pricing of enterprise offering against the price of creating/implementing required pieces, like custom Api Developer Portal.

For hosted solution, the following options is considered

* [AWS](https://aws.amazon.com/api-gateway/api-management/)
* [Microsoft Azure API Management](https://azure.microsoft.com/en-us/services/api-management/)
* [Google Apigee Edge](https://apigee.com/about/cp/open-source-api-management)

Downside is that they are all platform dependent, to the owners proposed platform with more limited on-premise options. These are all top of the line tools according to capabilities.

For all considered tools we need to check what underlying software components are required. For example, data storage, queuing, and logging capacity. We need to take into consideration effort and ability to build Developer portal, compared to customizing the tool offering.

Other tools that we looked at did in our opinion lack functionality or other ability for further considered, even though many of them could be considered. Note that the list provided is not all existing Api Management tools, so other options might apply.

### Positive Consequences

* Api Management tools are listed and grouped based on if they have open source option or not.

### Negative Consequences

* All considered options are vendor lock in.

## Pros and Cons of the Options

### [Google Apigee Edge](https://apigee.com/about/cp/open-source-api-management)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: At least one large company is using ApiGee.

Full blown API Management Platform from Google.

* Good, considered leader by both Gartner and Forrester
* Good, number 1 product in Gartner.
* Good, number 3 product in Forrester.
* Good, offers lot of functionality, and easy to use. `Gartner`
* Good, big market presence. `Forrester`
* Bad, complex to install on site. `Gartner`
* Bad, prices are higher. `Gartner`
* Bad, cloud offerings are only available on Google Cloud.

### [Mulesoft Anypoint](https://www.mulesoft.com/platform/api-management)

Price: To be requested. Partners in Iceland: Unknown Usage in Iceland: Unknown

Full blown API Management Platform from Mulesoft. Mulesoft products combine Application Integration and API management in product suite. Mulesoft is based on open source core product Mule. [GitHub](https://github.com/mulesoft/mule), but API management components are not open source. Mulesoft was acquainted by SalesForce 2018.

* Good, considered leader by Gartner and strong performer by Forrester
* Good, number 2 product in Gartner.
* Good, because chosen option for Australia gov.au platform.
* Good, because Mulesoft offers stand-alone offering for API Management.
* Consideration, what happens with ownership of SalesForce.

### [Software AG API Management](https://softwareaggov.com/products/integration/webmethods-api-management/)

Price: 500.000ISK per month based on 3.000.000 API calls per month. (To be negotiated). Partners in Iceland: Advania.

Usage in Iceland: 3 Installations for customers. Full blown API Management Platform from Software AG. Software AG products combine Application Integration and API management in product suite. Software AG products are not open source.

* Good, considered leader by both Gartner and Forrester
* Good, number 3 product in Gartner.
* Good, number 3 product in Forrester.
* Good, offers stand-alone offering for API Management.

### [IBM API Connect](https://www.ibm.com/cloud/api-connect)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: Unknown

Full blown API Management Platform from IBM. API Connect from IBM is not open source.

* Good, considered leader by both Gartner and Forrester
* Good, number 1 product in Forrester.
* Good, number 4 product in Gartner.

### [Axway Ampify](https://www.axway.com/en/products/api-management)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: Unknown

Full blown API Management Platform from Axway. Axway products combine Application Integration and API management in product suite. Axway products are not open source.

* Good, considered leader by both Gartner and strong performer by Forrester
* Good, offers stand-alone offering for API Management.

### [Tibco Mashery](https://www.tibco.com/products/api-management)

Price: Needs request. Partners in Iceland: Advania. Usage in Iceland: Unknown

Full blown API Management Platform from Tibco. Tibco products combine Application Integration and API management in product suite. Tibco products are not open source.

* Average, considered visionary by Gartner and strong performer by Forrester.
* Good, offers stand-alone offering for API Management.

### [AWS](https://aws.amazon.com/api-gateway/api-management/)

Price: Needs request. Partners in Iceland: [Andes](https://andes.is), others Usage in Iceland: Unknown

Full blown API Management Platform from AWS.

* Good, in 2018, AWS’s revenue from Amazon API Gateway grew by a market-leading 160% year over year, far above the market average of 31%. `Gartner`
* Average, considered challenger by Gartner
* Consideration, AWS indicates that their product can be installed on premise, but most reviews point out that it is Cloud only offering.
* Bad, AWS doesn’t offer a customer-managed gateway, which is critical technology for many organizations operating in highly secured and restricted on-premises environments. However, its AWS Outposts offering, which provides AWS services on-premises (managed, maintained and supported by AWS), is in preview at the time of writing. `Gartner`

### [Akana by Perforce](https://www.akana.com/)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: At least two large installations

Full blown API Management Platform from Perforce. The Solution has been purchased twice in recent years. First by Rouge Software, then by Perforce in 2019. This product was on top of Gartner report some years ago, but small presence and evolution in other tools has put them bit back.

* Bad, small market presence `Forrester`
* Average, moderate customer satisfaction with product usage `Forrester`
* Bad, low satisfaction with the vendor `Forrester`

### [Sensedia](https://sensedia.com/)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: Unknown

To get further information about Sensedia product we need to register email and read whitepapers. Review is based on Gartner / Forrester report.

* Average, considered visionary by Gartner and strong performer Forrester
* Good, Sensedia is one of the few vendors in this market to support the growing demand for the creation and management of GraphQL endpoints. `Gartner`
* Bad, Although Sensedia has been hiring local staff and has begun to expand into Europe, it still has limited reach beyond its home country of Brazil. `Gartner`
* Bad, Small market presence `Forrester`

### [Kong Community Edition](https://konghq.com/)

Price: Open Source. Partners in Iceland: N/A Usage in Iceland: Community edition is used in small setup, but not advertised.

Kong Community Edition is Open Source API Gateway. [GitHub](https://github.com/Kong). The tool is managed by Rest services. There are quite few Open Source Admin tools like Konga (<https://pantsel.github.io/konga/>) and (<https://github.com/pocketdigi/kong-admin-ui>) that can be used to manage the API Gateway. Everyone can write their own plugin to the product, and it has variety of options advertised (<https://docs.konghq.com/hub/>), Many plugins are only available in Enterprise edition of the product, which require subscriptions and they are not Open Source. As a user you still have ability to either create your own plugin or find plugin for your need in Open Source community. For example plugin for OpenID Connect requires enterprise edition, but we can still find contributed plugin for that functionality (<https://github.com/Optum/kong-oidc-auth>). The Community edition does not have Open Source Developer Portal. We have found at least one Open Source Portal on top of Kong (<https://github.com/Haufe-Lexware/wicked.haufe.io>). Kong does not natively support OpenAPI, but plugin is available to define OpenAPI spec url to an endpoint. There are also some paid solutions built on Kong Gateway. All GraphQL plugins are part of Enterprise Edition. Risk factor is that future additions to Kong, will aim on Enterprise Edition.

### [Kong Enterprise Edition](https://konghq.com/)

Price: Request needed with NDA signature. Partners in Iceland: Unknown Usage in Iceland: Unknown

By using Kong Enterprise edition, more plugins and support can be obtained by Kong. In addition you get customizable Developer Portal, Analytics tools and various developer tools. The add on features are not open source, and provides a Kong vendor lock in. Kong provides Enterprise Edition of the Product, that includes API Developer Portal, and Development Tools. Kong is built on NginX.

* Average, considered visionary by Gartner.
* Good, large open source community, over 180 contributors and 25000 GitHub stars.
* Good, large range of installation modules.
* Good, provides maintenance and support for large enterprise.
* Good, API Interface for managing the gateway.
* Bad, little SOAP support.

### [Red Hat 3Scale](https://www.3scale.net/)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: Unknown

Red Hat 3Scale is open source API gateway [GitHub](https://github.com/3scale/APIcast). It needs license for usage.

* Average-, considered visionary by Gartner and contender by Forrester
* Good, fully open source product. All offerings are open source.
* Good, company has good market presence `Forrester`
* Consideration, small community, 28 contributors 196 GitHub stars

### [WSO2](https://wso2.com/api-management/)

Price (Unsupported Version): Open Source. Price: 11400 EUR Per Core / per year. For 4 Cores it would be 600.000ISK per month. (To be negotiated). Partners in Iceland: N/A Usage in Iceland: Unknown

WSO2 is open source API management tool. It can be obtained from GitHub without support, but Paid option includes support and fixes. The unsupported version provides all functionality, including Developer Portal and API Gateway Administrative user interface. However, no fixes, and support is provided. During our research we found out that to run the product in Production environment, user must work around through bugs that are in the base versions. Bug fixes are not available in the community edition. Downloaded bundles from WSO2 site may not be used in production Environment. They include WS02 license that prohibit production usage without support subscription. Risk factor is that the product is moving to full license module.

* Average+, considered visionary by Gartner and leader by Forrester
* Good, number 4 product in Forrester.
* Good, decent open source community, 144 contributors and 410 GitHub stars.
* Good, fully open source product. All offerings are open source.
* Consideration, recent change in license model, directing customers to paid support.

### [Tyk Open Source Edition](https://tyk.io/)

Price: Open Source. Partners in Iceland: N/A Usage in Iceland: Unknown

This Open Source offering is similar to Kong Community edition. Only the API gateway of the product is Open Source, and it is managed by Rest Services. The community is smaller than Kong even though it has 5600 stars on GitHub. Like in Kong, Plugin can be created, but does not contain as extensive inventory of plugins as Kong.

### [Tyk](https://tyk.io/)

Price: Starting price $450 per month. Partners in Iceland: N/A Usage in Iceland: Unknown

Full blown API Management Platform from Tyk. Tyk provides open source API Gateway described above. In addition the paid version of the program includes Tyk API Dashboard, Designer, Analytics and Developer Portal.

* Average, considered strong performer by both Gartner and Forrester
* Good, API Gateway is free to use for all forever according to homepage.
* Good, good open source community, 62 contributors and 5600 GitHub stars.
* Bad, Small market presence `Forrester`

### [Dell Boomi](https://boomi.com/)

Boomi is full blown API Management Platform from Dell. This is enterprise solution, and not open source.

* Average-, considered nice player by Gartner.
* Bad, score lowest of all vendors in Gartner report.

### [Microsoft Azure API Management](https://azure.microsoft.com/en-us/services/api-management/)

Price: Premium \~$2,795.17/month.

Api management platform from Microsoft. This platform is easy to install and operate in the Azure cloud. The prefered pricing option is the premium one. In the premium pricing option you have the ability to have self hosted gateway, that can be executed on prem for network latencey. All management is however done from the Azure cloud.

* Good, considered leader by both Gartner and Forrester
* Consideration, Microsoft indicates that their product can be installed on premise via VLAN, but most reviews point out that it is Cloud only offering.
* Bad, Azure API Management is an Azure cloud service and will remain focused on developers’ and IT professionals’ priorities to build, deploy and manage applications through Microsoft’s global cloud. It’s unlikely to evolve in response to the main business drivers of digital transformations, in contrast to most other offerings in this market. `Gartner`

### [Nginx Plus](https://www.nginx.com/)

Price: For Nginx plus, yearly price for software is $2500. Partners in Iceland: Unknown Usage in Iceland: Unknown

Nginx offers API management in Nginx Plus and Nginx Controller product. Nginx Plus is a API Gateway, and API Management features like developer portal and management / registration interface is provided with API management plugin on NginX Controler. Nginx Plus and NginX Controller are not open source products. Ngin

* Good, NginX open source reverse proxy is widely used as component in other API Management solutions.
* Bad, did not find many information about distribution and usage.

### [Broadcom Layer7](https://www.broadcom.com/products/software/api-management)

Price: Needs request. Partners in Iceland: Unknown Usage in Iceland: Unknown

Layer7 is full blown API Management Platform from Broadcom. Layer7 is not open source product.

* Average-, considered nice player by Gartner
* Bad, drops from leader in Gartner report. `Gartner`

### [KrakenD](https://www.krakend.io/)

Price: Open Source. Partners in Iceland: Unknown Usage in Iceland: Unknown

Krakend offers open source API Gateway. Tool is intended to create REST interface to combine many calls to backend system.

* Consideration, small community, 17 contributors but 2700 GitHub stars
* Bad, no developer portal.
* Bad, tool not intended as API Management tool, only gateway to combine microservice in single platform.

### [Netflix Zool](https://github.com/Netflix/zuul)

Price: Open Source. Partners in Iceland: Unknown Usage in Iceland: Unknown

Zool is open source API Management Tool by Netflix, [GitHub](https://github.com/Netflix/zuul) Zool is purpose was to serve as backend of the NetFlix streaming application.

* Good, 66 contributors and 9400 GitHub stars.
* Consideration, 66 contributors but very small activity on GitHub.
* Consideration, designed for use with Netflix.
* Bad, no Api Development Portal.
* Bad, Last release nearly one year ago.

### [Api Umbrella](https://apiumbrella.io/)

Price: Open Source. Partners in Iceland: Unknown Usage in Iceland: Unknown

Open source API management tool by National Renewable Energy Laboratory. Open source [GitHub](https://github.com/NREL/api-umbrella)

* Consideration, 66 contributors but very small activity on GitHub.
* Bad, latest release over one year ago.

### [Express Gateway](https://www.express-gateway.io/)

Price: Open Source. Partners in Iceland: Unknown Usage in Iceland: Unknown

According to homepage, initial purpose as microservices API Gateway. Open Source [GitHub](https://github.com/ExpressGateway/express-gateway)

* Bad, no support for OpenAPI, requested in GitHub 2018 without implementation.
* Bad, 26 contributors, and very small activity on GitHub.

### [Gravitee.io](https://gravitee.io/)

Price: Open Source. Partners in Iceland: Unknown Usage in Iceland: Unknown

According to homepage, initial purpose as microservices API Gateway. Open Source [GitHub](https://github.com/gravitee-io).

* Good, 995 Github stars.
* Bad, only 16 contributors, and very small activity on GitHub.
* Consideration, currently creating paid Enterprise edition to address all change requests.

## Links

* [`Gartner`](https://www.gartner.com/) Magic Quadrant for Full Life Cycle API Management, Published 9 October 2019
* [`Forrester`](https://www.forrester.com/) The Forrester Wave™: API Management Solutions, Q4 2018
* [`Forrester`](https://www.forrester.com/) The Forrester Wave™: API Management Solutions, Q3 2020


# Viskuausan Static Site Generator

* Status: accepted
* Deciders: devs
* Date: 2020-09-07

We're going to create a web app for Viskuausan (API Catalog). Viskuausan consists of three main components:

* Web service catalogue
  * Displays an overview of web services.
  * Displays details about each web service.
* Data definition catalogue
  * Displays an overview of data definitions
  * Displays details about each data definition
* Design guidelines
  * Static text content describing best practices for API development

The two catalogue components require:

* Data storage
* API communication
* API GW and X-Road integration
* Other custom implementations

The design guidelines component require:

* Static content written in markdown

## Context and Problem Statement

Viskuausan is proving to be more complex and larger platform than just a simple documentation site from static content. Which React framework provides the most out-of-the-box features that we need?

## Decision Drivers

* Should use NodeJS and React as outlined in [SÍ technical direction](https://github.com/island-is/island.is/blob/main/handbook/technical-direction.md)
* Should be able to support markdown content rendered to HTML
* Should be open source
* Should be customizable to island.is UI design

## Considered Options

* [Docusaurus v2](https://v2.docusaurus.io/)
* [GatsbyJS](https://www.gatsbyjs.org/)
* NextJS + NestJS

## Decision Outcome

Chosen option: NextJS + NestJS

NextJS is the chosen web framework for all island.is websites needing server side rendering. As Viskuausan will probably be merged with island.is main website, creating it using same frameworks makes it easy to merge later on. It is easier to reuse Island UI components using NextJS over Docusaurus. Docusaurus main advantage over Next is out-of-the-box markdown support but it is easy to add markdown support in NextJS using [Remark](https://github.com/remarkjs/remark) library.

NestJS is used to create backend services and Viskuausan needs few backend services related to the X-Road and API GW integrations. Provides functionalities like ORM, dependency injection, unit testing.

## Pros and Cons of the Options

All of the considered options are built using React, are open source and popular site generators.

### Docusaurus v2

* Good, because it focuses on documentation
* Good, because it supports TypeScript
* Good, because it is extendable via plugins & themes
* Good, because it is ready for translations
* Good, because it supports document versioning
* Good, because it has content search out-of-the-box
* Bad, because it is still in beta
* Bad, because it requires manual setup for typescript compile-time type checking
* Bad, because it needs manual setup for ORM, dependency injection, testing and more.
* Bad, because it is not suitable for larger websites which needs more backend

  api functionality.

### Gatsby

* Good, because it has rich ecosystem of plugins
* Good, because it supports TypeScript
* Good, because it is really flexible
* Good, because it has GraphQL support for external data
* Bad, because it has high project complexity
* Bad, because it has high learning curve
* Bad, because it requires manual setup for TypeScript compile time type checking

### NextJS + NestJS

* Good, because it is flexible
* Good, because it supports TypeScript
* Good, because it is already in use in the monorepo
  * Will make it easier to move into the island.is web
* Good, because it is easy to use islandis-ui components
* Bad, because it requires customization to render markdown
  * Is relatively easy using [Remark](https://github.com/remarkjs/remark)

### Other honorable mentions

* [Docz](https://www.docz.site/)

  Built using Gatsby so we would rather go with Gatsby than Docz so

  unnecessary to list as an option


# Use OAuth 2.0 and OpenID Connect As Protocols for Authentication and Authorization

* Status: accepted
* Date: 2020-06-02

## Context and Problem Statement

What protocol(s) shall we use as the new standard for authentication and authorization. It would be supported by our new centralized authority server and should be implemented in all new clients and resource systems needing authentication or authorization. A requirement might be made that the authority service need to support other protocols for legacy systems but all new systems should be encourage to use the same protocol.

## Decision Drivers

* Secure
* Well defined and well reviewed standard
* Easy to implement by client and resource systems
* Support for non web client systems i.e. mobile devices

## Considered Options

* OAuth 2.0 + OpenID Connect
* SAML 2.0

## Decision Outcome

Chosen option: "OAuth 2.0 + OpenID Connect", because it is secure and well examined and and has support libraries for our tech stack.

## Pros and Cons of the Options

### OAuth 2.0 + OpenID Connect

* Good, because the authentication protocal is designed specifically to work with the authorization protocol.
* Good, because it supports non web clients i.e. native apps.
* Good, because it has certified, open source libraries for relying parties for OpenID authentication that match our

  tech stack (javascript with typescript defenitions).
* Bad, because it could require large tokens for authorization for multiple services, or split up tokens complicating

  the process.

### SAML 2.0

* Good, because it is the currently used standard for legacy systems.
* Bad, because it doesn't have good support for non web clients.
* Bad, because main focus is on enterprise SSO, not centralized authorization.


# Unified Naming Strategy for Files and Directories

* Status: accepted
* Deciders: devs
* Date: 2020-07-03

## Context and Problem Statement

As of the date of this writing, there are multiple different naming styles used in the monorepo, mostly because NX has defaults that differ between schematic types. In order for navigating the monorepo in a consistent rational manner, we should align on naming strategy for files and directories.

## Decision Drivers

* Provide consistency when navigating the codebase
* The earlier we decide on this, the better

## Considered Options

Some mixture of these:

* kebab-case
* PascalCase
* camelCase
* snake\_case

## Decision Outcome

Chosen option: Name files after their default export. If that default export is a React Component, or a class, then the file name should be in PascalCase. Otherwise, the filename should be in camelCase. Basically, for naming files avoid using kebab-case and snake\_case and make sure the name follows the default export of the file.

Naming directories should follow these guidelines: Only use kebab-case when naming NX apps and libraries, or folders containing apps and libraries, e.g. `island-ui` instead of `islandUi`: `import { Box } from '@island.is/island-ui/core'`

Use PascalCase for directories only containing React components:

```
components/CtaButton/index.ts
import 'components/CtaButton'
```

or:

```
components/CtaButton/CtaButton.tsx
import 'components/CtaButton/CtaButton'
```

rather than

```
components/cta-button/CtaButton.tsx
```

In all other cases, use camelCase.

### Positive Consequences

* Easier to navigate the codebase
* File names are more readable, and developers know what to expect
* This approach is the most common practice, and something most JS and TS developers are familiar with.


# CMS

* Status: accepted
* Deciders: devs, management
* Date: 2020-05-25

## Context and Problem Statement

island.is will be maintaining and publishing content from many different government agencies and institutions. Their technical skill may vary a great deal, the content skill may also be lacking, therefore it is paramount for the system to be user friendly and intuitive.

Agencies and institutions should have enough autonomy with regards to editing content they are responsible for, to minimise the manual labour required by the island.is editors.

Which CMS system would best suit the needs of island.is?

## Decision Drivers

* Content needs to be editable by non technical users
* Content needs to be accessible across multiple domains and platforms
* Setup should be simple for developers new to the project
* The system should manage flexible content structures to limit systems impact on design
* The system should be user friendly and easy to use for a non technical person
* The system needs to offer a suitable workflow option to ease content management once multiple agencies start to contribute

## Considered Options

* [Gather content](https://gathercontent.com/)
* [Prismic](https://prismic.io/)
* [Contentful](https://contentful.com/)
* [Content stack](https://www.contentstack.com/)
* [Whitehall](https://docs.publishing.service.gov.uk/apps/whitehall.html)
* [Drupal](https://www.drupal.org/), [WordPress](https://wordpress.org/), [Strapi](https://strapi.io/), other hosted solutions

## Decision Outcome

Devs narrowed the choice down to two options Contentful and Contentstack.

Both systems meet the required featureset.

A decision from management was made to use Contentful. Contentful is deemed to have a larger presence in the Icelandic dev community. Contentful is also believed to have a stronger funding base. Contentful is already implemented in some of our projects.

## Pros and Cons of the Options

### [Gather content](https://gathercontent.com/)

* Good, because it allows for a great deal of workflow and collaboration features
* Good, because it can function as a project management tool for the content
* Good, because it can serve as a communication portal between island.is and the various parties involved
* Good, because it has comprehensive access control \[7],\[8]
* Bad, because it has a very basic API
* Bad, because it has a limited set of CMS features
* Bad, because it is not designed to be a publishing platform

### [Prismic](https://prismic.io/)

* Good, because it is kind of a simpler version of Contentful
* Good, because it is simple to use for non technical users
* Good, because image editing & placement is simple but effective
* Good, because it has a built-in CDN for images
* Bad, because it doesn't have a write API
* Bad, because the only way to import content is through the web interface
* Bad, because it doesn't have 'required fields'
* Bad, because API is somewhat limited

### [Contentful](https://contentful.com/)

* Good, because it has a best in class API and SDKs
* Good, because it has a large ecosystem of users
* Good, because it has a hybrid WYSIWYG editor, where you mix content types together with regular rich text content
* Good, because it is generic enough to be used for many different things
* Good, because it has a write-API, so you can create content programmatically
* Good, because it can be extended with UI extensions and various 3rd party tools
* Good, because it has rich access controls
* Good, because it a lot of developers have experience with it
* Good, because it has a built-in CDN for images and content
* Good, because it can define workflows and apply user permissions across those
* Bad, because it has a very generic structure and can be confusing for new users
* Bad, because depending on how content is set up, you may often have to do deep drill-downs on content entries
* Bad, because it has a complex billing structure making it harder to project costs

### [Contentstack](https://www.contentstack.com/)

* Good, because it is somewhat structured compared to some of the other choices
* Good, because it has an SDK for many languages
* Good, because it is generic enough to be used for many different things
* Good, because it has a write-API, so you can create content programmatically
* Good, because it can be extended with widgets and various 3rd party tools
* Good, because it has a built-in CDN for images and content
* Good, because it has rich access controls
* Good, because it can define workflows and apply user permissions across those
* Good, because it has a easy to understand billing structure
* Bad, because fewer developers have experience with it
* Bad, because it has a steep initial price

### [Drupal](https://www.drupal.org/), [WordPress](https://wordpress.org/) and other hosted solutions

* Good, because you have endless control over these types of systems
* Good, because there's a huge ecosystem of pre-built stuff
* Bad, because the huge ecosystem has a huge quality control problem
* Bad, because you will need specialised knowledge of these systems to maintain them and get out of them what you want.
* Bad, because you will have to host them yourself, take care of backups and maintenance and there are regular serious security breaches with these systems.
* Bad, because even though they can be run in headless mode, their UIs and APIs are not really geared towards headless usage.

### [Strapi](https://strapi.io/)

* Good, because you have endless control over these types of systems
* Good, because there's a huge ecosystem of pre-built stuff
* Good, because it has a write-API, so you can create content programmatically
* Bad, because you will need specialised knowledge of these systems to maintain them and get out of them what you want.
* Bad, because you will have to host them yourself, take care of backups and maintenance and there are regular serious security breaches with these systems.
* Bad, because the system is missing features deemed critical such as content internationalization and granular access control

### [Whitehall](https://docs.publishing.service.gov.uk/apps/whitehall.html)

* Good, because it manages workflows
* Bad, because it's built around Gov UK and we would have to fork the project to use it safely
* Bad, a lot of upfront work would be required to adapt the system to our stack
* Bad, because it does not fulfill the project's requirements

## Links

[gather content ACL tab 1](https://share.getcloudapp.com/NQuD7WWP?embed=true)

[gather content ACL tab 2](https://share.getcloudapp.com/04uP5684?embed=true)


# Open Source License

* Status: proposed
* Deciders: dev, devops, managers
* Date: 2020-06-07

## Context and Problem Statement

It is the offical policy of the Digital Iceland and stated in the Techical Direction that it is to be implemented as free and open source. Open source software by definition is open to anyone to use, modify, distribute and study. These permissions are enforced an open source license. There are a number of well-known and widely used open source licenses available and we need to choose a license that best fits the goals of digital iceland.

There are two main types of open source licences: more permissive licences that confer broad freedoms and minimal obligations (e.g., the MIT, BSD and the Apache 2.0 licences); and sharealike licences that require licensing adaptations with the same licence if they distribute them (e.g., the GNU GPL).

Development for Digital Iceland will be open and free with minimum complications for development for all involved. Reuse and transparency will be promoted.

## Decision Drivers

* The primary motivation is to encourage, co-development, collabiration, transparency and reuse of the software.
* It is important to build on the experience of similar government led inititives in other countries.
* Digital Iceland has no patents or intellecatual property that needs to be protected or guarded by the license chosen.
* It is not a concern for Digital Iceland that the license restricts usage in other projects, be it open or closed source.

## Considered Options

The different licenses

* Apache
* BSD
* GNU GPL
* MIT

## Decision Outcome

The MIT license was chosen, for the following reasons:

* It is the least restrictive of the licenses.
* It is very consise, simple and easy to understand and therefore should be clear to users and developers.
* Digital Iceland does not require protection of patents or existing intelletual property.
* Well known government lead initiatives like uk.gov and X-Road use the MIT license.
* The MIT license is the best known and most widely used free and open-source license in the world.

## Pros and Cons of the Options

### Apache

* Good, because is well known and very permissive like the MIT license.
* Bad, it is has restrictions around redistribution that do not apply for Digital Iceland.
* Bad, is way very long and wordy and therefore requires more effort to understand.

### BSD

* Good, because is well known and very permissive like the MIT license.
* Bad, because it has restrictions about using the names of the copyright holder which is not a concern for digital Iceland.

### GNU GPL

* Good, because it is very well known.
* Bad, that it is not permissive and requires derived software to adopt the license as well.

## Links

* [Stjórnarráðið - Umfjöllun um opinn hugbúnað](https://www.stjornarradid.is/verkefni/upplysingasamfelagid/stafraent-frelsi/opinn-hugbunadur)
* [Ríkisendurskoðun - Frjáls og opinn hugbúnaðr](https://rikisendurskodun.is/wp-content/uploads/2016/01/Frjals_og_opinn_hugbunadur_01.pdf)


# What Chart Library Should We Use Across Island.is?

* Status: proposed
* Deciders: designers and developers of island.is
* Date: 2020-11-23

Technical Story: Select a chart library which fulfills all requirements for implementing charts on island.is

## Context and Problem Statement

Multiple projects need to show data visually using charts and graphs. In order to provide unified look and feel across island.is we should commit to a single approach to implementing charts, i.e. choose one library for the whole repository.

## Requirements

The charting library should:

* support rendering all standard charts, i.e. bar, line, pie,
* support custom styling of elements (colors, fonts, tooltips, legends, axis)
* support lazy/dynamic loading to minimize js bundles
* Typescript support

## Decision Drivers

* Meet all requirements listed above
* API quality
* Pricing
* Bundle size
* Typescript support

## Considered Options

* [Recharts](http://recharts.org/)
* [Chart.js latest stable version](https://www.chartjs.org/)
* [Chart.js 3.0.0 beta](https://www.chartjs.org/docs/next/getting-started/installation/)
* [Nivo](https://nivo.rocks/)
* [react-vis](https://uber.github.io/react-vis/)

## Decision Outcome

Chosen option: "Recharts", because it meets all requirements, and overall has a very nice, dev-friendly API. It is the most popular (downloads per week) react charting library on github, and recommended across the community. We can customize how it looks, and start using it quickly without much groundwork.

### Positive Consequences

* We can start implementing charts and graphs as needed in island.is

### Negative Consequences

* It is a big dependency, but almost all chart libraries are big due to their nature. We will minimize the impact of this by enforcing charts to be lazy loaded in our codebase.

## Pros and Cons of the Options

### Recharts

* Great, because it has a great API with composable chart components
* Great, because it allows customization of almost all chart elements
* Great, because it works beautifully with react
* Great, because it is tree-shakable
* Good, because it is battle tested and widely used across the community (510k weekly downloads, 15k github stars)
* Good, because it has typescript support
* Good, because it has no pricing
* Good, because there is a babel plugin which allows us to reduce the build output substantially
* Bad, because it is a big dependency (490.1 kb minified)

### Chart.js version 2.9.8 (latest stable version)

* Good, because it is battle tested and widely used across the community (1,273,958 weekly downloads, 51.1k github stars)
* Good, because it has typescript support
* Good, because it has no pricing
* Neutral, because it is not written for React, but it has a react wrapper package we can use to simply use it in our React code
* Bad, because it is pretty outdated and is due to be majorly refactored in version 3.0 which breaks backwards compatibility
* Bad, because it is a big dependency (459.6 kb minified)
* Bad, because its API is a bit bloated for doing simple things like custom tooltips

### Chart.js version 3.0.0-beta

* Great, because it is a relatively small dependency (154.1 kb minified)
* Great, because it is tree-shakable
* Good, because its API has been improved vastly over the latest stable version
* Good, because it has typescript support
* Good, because it has no pricing
* Bad, because it is still in beta
* Bad, because its API is a bit bloated for doing simple things like custom tooltips
* Bad, because if we opt in to use the beta version, we will have to implement our own react wrapper so it can be quickly used across our codebase

### Nivo

* Great, because it allows customization of almost all chart elements
* Great, because it works beautifully with react
* Great, because it is tree-shakable
* Good, because it has server side rendering
* Good, because it supports more exotic chart types in addition to the standard ones
* Good, because it has online storybook for documentation
* Good, because it has typescript support
* Good, because it is in very active development
* Good, because it has a very robust documentation
* Bad, because it is not as widely used nor battle tested as Chart.js or recharts
* Bad, because it is a big dependency (389.5 kB minified)
* Bad, because in practice its API is inferior to recharts (this is opinionated)
* Bad, because it can be hard to find what you are looking for in the documentation

### react-vis

* Great, because it is tree-shakable
* Good, because it works with react
* Good, because it has online storybook for documentation
* Good, because it has typescript support
* Bad, because in practice its API is inferior to most of the other options (this is opinionated)
* Bad, because we need to import their stylesheet, which in turn does not provide as nice styling API as the other choices
* Bad, because it is a relatively big dependency (313 kb minified)
* Bad, because it looks like there is no active development

## Links

* [Best react chart libraries](https://openbase.io/categories/js/best-react-chart-libraries)
* [Recharts](http://recharts.org/)
* [Chart.js latest stable version](https://www.chartjs.org/)
* [Chart.js 3.0.0 beta](https://www.chartjs.org/docs/next/getting-started/installation/)
* [Nivo](https://nivo.rocks/)
* [react-vis](https://uber.github.io/react-vis/)


# What Feature Flag Service/application Should We Use at Island.is?

* Status: accepted
* Deciders: developers and product owners of island.is
* Date: 2021-01-18

Technical Story: Select a feature flag solution that gives us the ability to easily use feature flags across our solutions.

## Context and Problem Statement

We want to be able to roll out new features gradually, perform A/B testing and target individual groups with a new feature. Also, we want to be able to flip a switch to turn features on or off for everyone.

## Decision Drivers

* Ease of setup
* Ease of maintenance
* Cost
* Developer experience
* Usability/UX
* Operational concerns
* Handling of PII

## Considered Options

* [LaunchDarkly](https://launchdarkly.com/)
* [FlagSmith](https://www.flagsmith.com/)
* [Optimizely Rollouts](https://www.optimizely.com/rollouts)
* [Unleash](https://github.com/Unleash/unleash)
* [ConfigCat](https://configcat.com)
* [FeatureFlagTech](https://featureflag.tech)

## Decision Outcome

Chosen option: "ConfigCat", because:

* We can probably get away with using it for very low cost
* We can start using it almost right away with little configuration

If we decide later that we would like some of the features of LaunchDarkly, we want to be able to quickly swap. Thus, it is vital that we write some kind of service-agnostic wrapper.

### Positive Consequences

* We can start using feature flags across our stack.

### Negative Consequences

* Complexity of applications will increase

## Pros and Cons of the Options

### LaunchDarkly

* Good, because it has great UX
* Good, because it is the market leader and has a lot of customization options
* Good, because it allows developers to change flags in config files for local development
* Good, because it offers a relay proxy, minimizing outgoing connections
* Good, because setup is easy and maintenance is really low
* Good, because it has built-in support for multiple environments
* Good, because the provide private attributes to help with PII
* Good, because it has built-in datadog support
* Bad, because it's the most expensive of the considered options
* Bad, because it's hard to segment on PII

### FlagSmith

* Good, because it's free if self-hosted
* Good, because it has built-in support for multiple environments
* Good, because we can segment on PII since we store all the data
* Good, because devs could run their own instance for local development
* Bad, because we'd need to maintain it ourselves
* Bad, because it has quite low community activity on GitHub

### Optimizely Rollouts

* Good, because it's free for a low volume
* Good, because setup is easy and maintenance is really low
* Good, because it has built-in support for multiple environments
* Bad, because it's really hard to segment on PII
* Bad, because UI is hard to navigate
* Bad, because it doesn't seem to have a lot of open-source usage/examples
* Bad, because it only supports development environment inside the product
* Bad, because they don't have self-serve or an open price list
* Bad, because it's part of some larger stack that we're not using, and seems to be opinionated towards that

### Unleash

* Good, because it's free if self-hosted
* Good, because we can segment on PII since we store all the data
* Good, because devs could run their own instance for local development
* Good, because it has high community activity on GitHub
* Bad, because it doesn't come with built-in support for multiple environments
* Bad, because the UI is hard to navigate and counter-intuative in places
* Bad, because we'd have to implement authorization ourselves

### ConfigCat

* Good, because they don't base their pricing on MAU but config downloads
* Good, because they can be configured to store everythin in EU
* Good, because setup is easy
* Good, because it has built-in support for multiple environments
* Bad, because we would want to implement our own relay
* Bad, because it seems quite bare-bones compared to others
* Bad, because it only supports development environment inside the product
* Bad, because it's really hard to segment on PII

### FeatureFlagTech

* Good, because it's cheap
* Good, because setup is easy and maintenance is really low
* Bad, because we would want to implement our own relay
* Bad, because it doesn't support user segmentation or variations
* Bad, because their UI is horrible

## Links

* [LaunchDarkly read flags from files](https://docs.launchdarkly.com/sdk/concepts/flags-from-files)
* [Optimizely Rollouts Plans Comparison](https://www.optimizely.com/compare-rollouts-plans/)


# Logging, Monitoring and APM Platform

* Status: proposed
* Deciders: ops, devs, devops, managers
* Date: 2021-01-27

Technical Story: Using SaaS solution or build our own for logging, monitoring and APM(application performance monitoring)

## Context and Problem Statement

We need a central observability platform where we ingest all our logs, metrics and traces so that ops, devs and devops can analyze performance, reliability and uptime. We can try to build and host such a platform on our own or use SaaS providers like DataDog.

## Decision Drivers

* Reliability
* Feature-richness
* Cost
* Maintenance
* Development
* Vendor lock level

## Considered Options

* Self hosted: Elasticsearch + Grafana + Kibana + Logstash + Jaeger
* SaaS: DataDog

**Full disclosure: Andes ehf. is a DataDog partner. Andes ehf. would not be receiving any sort of kick-backs due to Stafrænt Ísland using DataDog services. Stafrænt Ísland would be in a direct relationship with DataDog.**

Special note about pricing comparison: This is a very high-level price comparison, which does not take into account the ever-growing consumption we will see but should give a rough idea of the balance of cost.

\| Self-Hosted | | | | | | | ----------------------------------- | ------------------ | ------------- | ------------------------- | --------------------------------- | -------------------------------------- | --- | | Factors | Fixed price, hours | Monthly hours | Monthly price without VAT | First year total cost without VAT | First two years total cost without VAT | | Development | 160 | 0 | 0 | ISK3,200,000.00 | ISK3,200,000.00 | | Infrastructure | 0 | 0 | $700.00 | ISK1,100,400.00 | ISK2,200,800.00 | | Monitoring | 8 | 0 | ISK10,000.00 | ISK280,000.00 | ISK400,000.00 | | Maintenance | 0 | 5 | 0 | ISK1,200,000.00 | ISK2,400,000.00 | | Total | | | | **ISK5,780,400.00** | **ISK8,200,800.00** | | | | | | | | | **SaaS** | | | | | | | DataDog | 0 | 0 | $1,750.00 | **ISK2,751,000.00** | **ISK5,502,000.00** | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Sample hourly rate without VAT, ISK | ISK20,000.00 | | | | | | ISK/USD | ISK131.00 | | | | |

## Decision Outcome

SaaS solution (DataDog) is a clear winner due to its hastle-free service usage, continuous improvement as well as its competitive pricing.

### Positive Consequences

* Easy access to observability for devs and devops
* Well known integration target for third-party services
* Monitoring setup is well known in the industry
* No special knowledge about setup of the plaftorm

### Negative Consequences

None.

## Pros and Cons of the Options

### Self-hosted

Elasticsearch + Grafana + Kibana + Logstash + Jagger + Prometheus

* Good, because it consists of open-source components which we can use
* Good, because it uses open protocols
* Good, because it is a relatively low cost running this stack
* Bad, because there are no ready Dashboards for our stack
* Bad, because we need to develop this package ourselves and it would be a while before we can use it
* Bad, because due to a disagreement between AWS and the company behind the open source Elasticsearch, there is some uncertainty about its future on the AWS platform
* Bad, because we need to operate this ourselves - run, monitor, upgrade, integrate addons

### DataDog

DataDog is a monitoring and APM platform that has a wide variety of integrations and continues to develop new ones

* Good, because it is a very feature-rich platform
* Good, because it allows having our data in the EU and complies with data regulations relevant to Iceland
* Good, because it is ready to use right now
* Good, because it supports open protocols
* Good, because it scales with usage
* Good, because it is run by someone else than us
* Good, because the company keeps adding new features that we can simply turn on
* Good, because devops have all this time to do other things specific to the problem domain
* Bad, because with increased usage comes increased markup

## Links

* [DataDog](https://datadoghq.com)
* [Prometheus](https://prometheus.com)
* [Elasticsearch](https://www.elastic.co)
* [Jaeger](https://www.jaegertracing.io)
* [Grafana](https://grafana.com/grafana/)


# Running Maestro mobile E2E tests in CI

* Status: proposed
* Deciders: app team, devops, managers
* Date: 2026-01-30

### Context and Problem Statement

We run end-to-end (E2E) tests for the [Ísland.is](http://xn--sland-ysa.is) mobile app using [Maestro](https://maestro.dev/) flows. We need a CI setup that is reliable on both iOS and Android, provides actionable debugging information when failures occur, and requires minimal maintenance.

We evaluated three approaches:

* Run Maestro tests inside our existing **Codemagic CI** using local simulators/emulators.
* Use a dedicated device-testing SaaS: **Maestro Cloud**.
* Use a dedicated device-testing SaaS: **devicecloud.dev**.

After effort, we got Maestro E2E tests green on iOS in Codemagic, but not on Android. Android runs are flaky, dominated by timeouts likely caused by limited/contended CI resources. Debugging failures in Codemagic is also slow because it is difficult to consistently extract high-quality artifacts (e.g., recordings and structured run reports).

Both SaaS device-cloud solutions “just work” operationally and provide UIs, recordings, and retry capabilities. However, Maestro Cloud is comparatively expensive, while devicecloud.dev appears to offer a better cost-to-value ratio, despite being a smaller operation.  &#x20;

### Decision Drivers

* **Reliability across platforms:** Reduce Android flakiness and timeout failures seen on Codemagic-hosted emulators.
* **Debuggability:** Provide fast access to artifacts (recordings, logs/reports) and a UI for triage.
* **Operational simplicity:** Avoid maintaining simulator/emulator infrastructure and artifact plumbing in CI.
* **Cost efficiency:** Keep recurring costs proportional to usage.

### Considered Options

* Option 1: **Codemagic-only** (run Maestro locally on Codemagic machines with emulators/simulators)
* Option 2: **Maestro Cloud**
* Option 3: **devicecloud.dev** &#x20;

### Decision Outcome

Chosen option: **Option 3 — devicecloud.dev.**

We will continue to build app binaries in Codemagic, but we will execute Maestro flows on devicecloud.dev for both iOS and Android.

Rationale:

* It natively supports running Maestro flows.
* It addresses the current core pain: Android flakiness from CI resource constraints.
* It significantly improves debugging via hosted UI, recordings, and artifact access.
* It is more cost-effective than Maestro Cloud while still providing a “device cloud” experience. &#x20;

**Positive Consequences**

* **Improved stability** for Android E2E compared to Codemagic-hosted emulator execution.
* **Better failure triage:** recordings and reporting are readily accessible and consistent.
* **Lower maintenance:** less time spent tuning CI machines, emulator settings, and artifact extraction.
* **Cost alignment:** better value than Maestro Cloud for our current scale.&#x20;

**Negative Consequences**

* **SSO may require enterprise-style purchasing:**
  * Maestro Cloud lists SSO under its Enterprise tier.&#x20;
  * devicecloud.dev offers enterprise SSO to orgs who have purchased $2000 or more in DeviceCloud credits.
  * Given the low security-risk and small number of active users (2–3), we accept non-SSO access for now, and will revisit if adoption grows or policy requires it.
* **External service dependency:** test execution relies on a third-party platform.
  * This is considered minor because Maestro flows are portable and we can switch vendors with relatively low effort.

### Pros and Cons of the Options

#### Option 1: Codemagic-only (local simulator/emulator execution)

Good, because:

* Keeps execution within existing CI without introducing a separate execution vendor.&#x20;

Bad, because:

* Observed Android flakiness/timeouts due to resource constraints.
* Harder to collect consistent, high-quality debugging artifacts compared to device-cloud solutions.
* Higher ongoing maintenance for stable emulator/simulator execution and artifact handling.

#### Option 2: Maestro Cloud

Good, because:

* Purpose-built hosted execution for Maestro with CI integration and cloud reporting.&#x20;

Bad, because:

* Cost: priced per device per month; comparatively expensive for our needs. When written, costs 250$ per device so total of 500$ for iOS and Android without parallelisation.
* SSO: listed as an Enterprise feature, which may be unnecessary at our current user count.&#x20;

#### Option 3: devicecloud.dev (chosen)

Good, because:

* Purpose-built hosted execution with a UI and artifact support designed for Maestro workflows.
* Cost effective: When written, costs around 0,1$ per flow or 2-3$ to run the full suite on iOS and Android. That's at most 100$ per month if we run the full suite every night.
* Includes 5x parallelisation for both platforms (depends on overall load).

Bad, because:

* SSO gating: enterprise SSO is available but requires meeting a minimum credit purchase threshold.&#x20;

### Trigger Strategy (CI scheduling)

We will run the full Maestro suite nightly, but only when there are app changes since the last successful nightly run (i.e., changes affecting the mobile app code or test flows).

Nightly runs provide a predictable cadence and reduce CI load/noise while still catching regressions quickly enough for the current workflow.

### Data / Security Considerations

* E2E tests must run using mock/non-sensitive test data only (no production identities, no real user data).
* Test artifacts (recordings, screenshots, logs) should therefore contain no sensitive information.
* Because the [Ísland.is](http://xn--sland-ysa.is) app is open source and the E2E suite is designed around mock data, sending binaries and flows to a device-cloud provider is considered a low security risk, provided we enforce the “no sensitive data” rule and store provider API keys as CI secrets.


# ADR Template

* Status: \[proposed | rejected | accepted | deprecated | … | superseded by ADR-0005 (add link)
* Deciders: \[list everyone involved in the decision]
* Date: \[YYYY-MM-DD when the decision was last updated]

Technical Story: \[description | ticket/issue URL]

## Context and Problem Statement

\[Describe the context and problem statement, e.g., in free form using two to three sentences. You may want to articulate the problem in form of a question.]

## Decision Drivers

* \[driver 1, e.g., a force, facing concern, …]
* \[driver 2, e.g., a force, facing concern, …]
* …

## Considered Options

* \[option 1]
* \[option 2]
* \[option 3]
* …

## Decision Outcome

Chosen option: "\[option 1]", because \[justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | … | comes out best (see below)].

### Positive Consequences

* \[e.g., improvement of quality attribute satisfaction, follow-up decisions required, …]
* …

### Negative Consequences

* \[e.g., compromising quality attribute, follow-up decisions required, …]
* …

## Pros and Cons of the Options

### \[option 1]

\[example | description | pointer to more information | …]

* Good, because \[argument a]
* Good, because \[argument b]
* Bad, because \[argument c]
* …

### \[option 2]

\[example | description | pointer to more information | …]

* Good, because \[argument a]
* Good, because \[argument b]
* Bad, because \[argument c]
* …

### \[option 3]

\[example | description | pointer to more information | …]

* Good, because \[argument a]
* Good, because \[argument b]
* Bad, because \[argument c]
* …

## Links

* \[Link type]\[link to adr]
* …


# Log Management Policy

Digital Iceland Log Management Policy

Log Management Policy&#x20;

### Digital Iceland Log Management Policy&#x20;

#### 1. Purpose&#x20;

The purpose of this policy is to document proper logging practices and ensure they are followed in Digital Iceland’s infrastructure and applications. The goal is to ensure availability, retention, integrity and evidentiary value of log data for troubleshooting, audit and security purposes and setting appropriate retention periods, access restrictions and storage requirements for logs in order to be compliant with relevant data protection laws and other legal requirements.&#x20;

#### 2. Scope&#x20;

This policy applies to all logs generated within the Digital Iceland infrastructure and applications developed and operated for Digital Iceland. This includes logs for activities performed by end-users, administrators and developers as well as automated system functions.&#x20;

#### 3. Definitions&#x20;

*Logs*: Logs are time-stamped records generated by IT systems that capture events, transactions, errors, and state changes for security monitoring, troubleshooting, compliance, and operational analysis.&#x20;

*Application Logs*: Logs created by user interaction with the application; or automated processes in the application e.g. error messages, execution flows, user activities primarily used for confirming or troubleshooting the correct function of the application and not for security or audit purposes.&#x20;

*Audit Logs*: Tamper-resistant records of events that track who accessed what resources, when, and what actions were performed, used for compliance, accountability and security investigations.&#x20;

*Infrastructure Logs*: Logs generated by the infrastructure that hosts the Digital Iceland services and applications.&#x20;

*Personally Identifiable Information (PII)*: Any data that can be used, alone or with other data, to identify, contact, or locate a specific individual, ranging from basic details like a National ID number (kennitala), name, phone number or address to highly sensitive data such as biometrics, health related- or financial info.&#x20;

*Hot Storage*: Storage infrastructure for logs that is highly available in the sense that with appropriate permissions they can be searched and interacted with, with a reasonably quick response time. Usually considerably more expensive than cold storage.&#x20;

*Cold Storage*: Storage infrastructure for logs that is not highly available, in the sense that additional action is required to make the logs searchable with a reasonably quick response time; such as re-ingesting into Hot Storage. Usually considerably more cost effective than hot storage.&#x20;

*Access-Controlled Systems*: A system that authenticates users and enforces authorization rules to restrict who can access what resources and keeps an Audit Log of access and system interactions.&#x20;

*Encryption at rest*: Encryption of data while stored on physical media (disks, databases, backups), including cloud storage, to protect against unauthorized access if storage devices are compromised or stolen.&#x20;

*TLS*: Transport Layer Security. A cryptographic protocol securing internet communications, like browsing (HTTPS), email, and messaging, by encrypting data to ensure privacy, integrity, and authentication, preventing eavesdropping and tampering.&#x20;

#### 4. Roles and Responsibilities&#x20;

Digital Iceland CTO (Tækni- og þróunarstjóri): In the scope of this policy; responsible, in place of the CISO if unavailable, to approve access to logs.&#x20;

Digital Iceland CISO (UT og öryggisstjóri): In the scope of this policy; final authority on security- and compliance related to access decisions and responsible, with backup from the CTO, to approve access to logs.&#x20;

Data Protection Authority (Persónuvernd): Compliance controller in the execution of this policy and data protection of Digital Iceland, as per regulation [90/2018: Lög um persónuvernd og vinnslu persónuupplýsinga](https://www.althingi.is/lagas/nuna/2018090.html). &#x20;

Data Protection Officer (Persónuverndarfulltrúi): Point of contact for data protection matters as per [Digital Iceland’s Privacy Policy](https://island.is/en/o/digital-iceland/personuverndarstefna-island-is/digital-iceland-data-protection-policy).&#x20;

National Archive of Iceland: Archival controller and archiving responsible for the execution of this policy and data storage of Digital Iceland records, as per regulation [77:2014: Lög um opinber skjalasöfn](https://www.althingi.is/lagas/nuna/2014077.html).&#x20;

#### 5. Compliance and regulations&#x20;

Logs can inherently contain sensitive information and especially so for a platform like Digital Iceland that due its role must process Personally Identifiable Information. The platform, the infrastructure it is hosted on and all the application components that the platform is composed of, adheres to [90/2018: Lög um persónuvernd og vinnslu persónuupplýsinga](https://www.althingi.is/lagas/nuna/2018090.html) and/or other applicable regulations at all times.&#x20;

#### 6. Storage and archive requirements&#x20;

As Digital Iceland is under the Ministry of Finance and Economic Affairs it must, generally, preserve all information that constitutes official records related to the execution of its legal duties as per [77:2014: Lög um opinber skjalasöfn](https://www.althingi.is/lagas/nuna/2014077.html) and be prepared to deliver said information to the National Archives of Iceland (Þjóðskjalasafn) for posterity.&#x20;

As per aforementioned regulation, Digital Iceland is required to safekeep all logs that record the execution of Digital Iceland’s duties and is only allowed to delete its records once the data has been securely handed over to the National Archives of Iceland or with express confirmation from the National Archives that the data can be deleted, with one exception see chapter 6.1 Modification and deletion. Handover to the National Archives should be done no later than as the data is 5 years old, to be compliant with [77:2014: Lög um opinber skjalasöfn](https://www.althingi.is/lagas/nuna/2014077.html).&#x20;

**6.1 Retention**&#x20;

Logs should be offloaded from expensive indexed systems (Hot Storage) and put into more cost effective cold storage as soon as is prudent while remaining appropriately accessible for the execution of Digital Iceland's duties and responsibilities as per applicable regulations.&#x20;

Audit Logs can be kept in hot storage for up to 1 year, after which they should be offloaded to cold storage, provided they do not form a part of an active investigation, legal hold or archival obligations. After which, it must be possible to re-ingest older logs back into hot storage for the purposes of lawful and compliant investigation and responding to legal inquiries up to but limited to the regulatory duty of Digital Iceland.&#x20;

Application Logs that are only useful for technical troubleshooting and are not the official record of the execution of Digital Iceland’s duties and responsibilities can be deleted after 1 year.&#x20;

**6.2 Modification and deletion**&#x20;

As per [90/2018: Lög um persónuvernd og vinnslu persónuupplýsinga](https://www.althingi.is/lagas/nuna/2018090.html), logs and records containing PII must be reliably accurate and updated or deleted as needed. Should inaccurate or inappropriate PII be discovered in logs, the finding should be well documented and express permission requested from Digital Iceland CISO or Digital Iceland CTO before proceeding with modification for the purposes of correction of an error or deletion, pursuant to compliance with applicable laws. All such approvals and actions must be documented and retained as part of the audit trail.&#x20;

Under no other circumstances should logs be modified and only with reference to requirements set forth in [77:2014: Lög um opinber skjalasöfn](https://www.althingi.is/lagas/nuna/2014077.html) can logs otherwise be deleted.&#x20;

#### 7. Security and access considerations&#x20;

Logs must be stored in secure, access-controlled systems with encryption at rest. If needed; in order to fulfil this or other requirements in this policy; logs may be stored in a fully separate environment from the environment generating or creating the logs.&#x20;

Data communication containing logs should always be encrypted in transit with TLS 1.3 or better.&#x20;

Application Logs may be accessible on an ongoing basis to authenticated developers approved, to have such access, by Digital Iceland CISO and/or Digital Iceland CTO.&#x20;

Infrastructure Logs may be accessible on an ongoing basis to authenticated DevOps Engineers, approved to have such access, by Digital Iceland CISO and/or Digital Iceland CTO.&#x20;

DevOps Engineers furthermore may have access to Audit Logs and Application Logs that contain PII in order to service legitimate requests for access to that information.&#x20;

Each individual access request to Audit Logs and Infrastructure- or Application Logs that contain PII, requires explicit permission from Digital Iceland CISO or Digital Iceland CTO before proceeding and only in the case of emergency (such as a time sensitive inquiry related to a security incident or police investigation) can this explicit permission be waived and Digital Iceland CISO and Digital Iceland CTO notified after the fact.&#x20;

In case of disagreement, the Digital Iceland CISO has final authority on security- and compliance related access decisions.&#x20;

**7.1 Tamper proof audit log and decision record**&#x20;

Access to logs needs to be logged itself (audit log of access to logs) in a tamper proof audit log (append-only and protected against modification or deletion). This log needs to include events of access, modification and deletion of log data.&#x20;

Additionally a system and procedure needs to be in place to ensure the accurate record of requests for access, modification or deletion to/of logs and the requests, any edits to the requests, actions performed documented as well as approvals from Digital Iceland CISO or Digital Iceland CTO. This record needs to be kept for traceability purposes and can be cross referenced with the tamper proof audit log of access to logs to get a full understanding of decisions and actions taken.&#x20;

#### 8. Data Minimization&#x20;

As per [90/2018: Lög um persónuvernd og vinnslu persónuupplýsinga](https://www.althingi.is/lagas/nuna/2018090.html), the collected PII should only be what is necessary for the execution of the duties of Digital Iceland. Recording of PII in logs should therefore be kept to only the essentials for any given record. PII should also only be kept in the sensitive identifiable form for as long as is necessary and if possible can be obfuscated (or hashed).&#x20;

#### 9. Approval, review and amendments of this policy&#x20;

This policy is reviewed annually, updated and any changes communicated to stakeholders, whenever there are significant changes to regulatory requirements, logging standards or infrastructure architecture. This policy in its entirety and any subsequent changes must be approved by Digital Iceland CISO or Digital Iceland CTO.&#x20;


# Developer Guidelines

These guidelines standardize how to write application logs across our backend services. Application logs should complement our infrastructure logs and APM to support troubleshooting in production. Our applications already emit standardized startup logs, as well as logs for inbound and outbound requests. As a developer, focus on logging actionable insights with a consistent structure and minimal noise.

{% hint style="info" %}
These guidelines apply to [island.is](http://island.is) application logs, usually logged through a Winston logger object. [Audit logs](https://github.com/island-is/island.is/tree/main/libs/nest/audit) have different goals and principles.
{% endhint %}

## **Principles**

* Log with purpose: every log line should help diagnose, alert, or audit.
* Prefer observability over verbosity: use metrics/traces for high-volume signals, logs for sparse, contextual events.
* Protect users: never log secrets, sensitive PII, or regulated data.
* Make correlation easy: ensure logs can be tied to traces, requests, and users without exposing sensitive data.

### What to log?

Log sparse, high-signal events that help you reconstruct what happened, when, and why—without duplicating what existing logs / traces already cover.

* Domain milestones and state changes.
* Background work.
* External dependencies and resilience.
* Unexpected but handled conditions.
* Context, ownership and stable non-sensitive identifiers for correlation.

Rule of thumb: log milestones and state transitions, not every step. If it’s actionable for on-call or essential to reconstruct a timeline—and not already covered by standard request/startup logs—log it.

### What not to log?

* Secrets: passwords, tokens, API keys, client secrets, private keys, session IDs.
* Personal data: kennitala, addresses, emails, phone numbers, full names, date of birth, financial details, health data.
* Full request/response bodies, especially for auth or external providers.
* Large objects/binaries, stack traces on known/handled errors, repeated identical messages in loops.
* Anything already logged by standard handlers (avoid duplicates).

## How to log?

### Use the appropriate log level

#### **Debug**

Use for developer diagnostics and detailed control flow. Typically visible only in local environments, but may be selectively enabled in production for short periods.

Example:

```tsx
logger.debug('Refund: Starting', { refundId })
logger.debug('Refund: Fetching payment information', { refundId })
logger.debug('Refund: Calling payment gateway', { refundId })
logger.debug('Refund: Finished', { refundId })
```

#### Info

Use for lifecycle events, domain events and meaningful state changes in production (e.g., service lifecycle, migrations, record changes, job processing, circuit closed, retry).

Be sure to include stable identifiers (non-sensitive) for correlation.

Example:

```tsx
logger.info(`Submitted application to ${organisation}`, { applicationId })
logger.info(`Finished processing attachments`, { jobId, applicationId })
logger.info(`Download failed, retry ${attempt} of 3`, { fileId, attempt })
logger.info(`Circuit breaker ${circuitName} closed`, { circuitName })
logger.info(`Could not update all licenses, returning from cache`, { error })
```

#### Warning

You should use warnings for unusual but handled conditions that may need attention (fallbacks, unexpected input, degraded mode, circuit open).

Example:

```tsx
logger.warn(`Error fetching ${organisation} licenses, skipping.`, { error, organisation })
logger.warn(`Validation failed`, { fieldErrors })
logger.warn(`Circuit breaker ${circuitName} open`, { circuitName })
```

#### Error

Log unexpected failures that require action or indicate deviating behavior.

In most cases, don’t log errors directly—let them bubble up to the standard error handler. The key exception is when you must catch all errors to apply fallback logic; in that case, log the unexpected errors at this level.

See more about handling and logging errors below.

Example:

```tsx
logger.error('Job failed', { error })
```

### **Group logs with context and ownership**

Use two stable fields on every log to make filtering and ownership clear:

* `context`: Identifies the producing component (e.g., SomeService, OrdersController, PaymentClient). Create a child logger per component so every log from it carries the same context.
* `codeOwner`: Identifies the development team responsible for the service, endpoint or resource (eg application template).

How to set `codeOwner`:

* Service-wide (infra): `app.codeOwner(CodeOwners.Name)` — applies to the entire backend service.
* Endpoint/class level: `@CodeOwner(CodeOwners.Name)` — on a controller, handler, or resolver.
* Call scope: `withCodeOwner(CodeOwners.Name, () => {})` — wraps a specific function or record-level operation.

Example:

```tsx
import type { Logger } from '@island.is/logging'

@Injectable()
export class SomeService {
	constructor(@Inject(LOGGER_PROVIDER) logger: Logger) {
		this.logger = logger.child({ context: 'SomeService' });
	}

	async doWork(id: string) {
		withCodeOwner(CodeOwners.SomeTeam, async () => {
			callSomethingWithLogging() // logs include codeOwner: CodeOwners.SomeTeam
			this.logger.info('Finished work', { id }); // log includes both context: 'SomeService' and codeOwner: CodeOwners.SomeTeam
		});
	}
}
```

You may also provide custom context fields to multiple log entries using `withLoggingContext`:

```tsx
*withLoggingContext*({ applicationId }, () => {
  callSomethingWithLogging() // logs include applicationId
})
```

### How to log errors

{% hint style="info" %}
Remember to think twice before logging errors (see below).
{% endhint %}

JavaScript Error objects have non-enumerable fields (e.g., stack) that won’t appear if you spread them into fields. Log the Error as the log message so the formatter can include those fields.

```tsx
// Don't:
logger.warn('Validation error', { error })
logger.error('Unexpected error', { error })
logger.error('Could not submit application', { error, applicationId })
logger.error('Error saving to database', { error })

// Do:
logger.warn(error)
logger.error(error)
logger.error({ message: error, applicationId })
logger.error({ message: error, action: 'Saving to database' })
// These log entries will include "message", "name", "code", "stack", "cause" and more from error.
```

### How to catch and throw new errors

When you need to translate an unexpected error into a different one (e.g., to drive frontend behavior or enrich request-level handling), wrap the original error using the [cause](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) option. This preserves the original error for logs while keeping it hidden from clients.

```tsx
try {
  // ...
} catch (err) {
  throw new Error('Failed saving to database', { cause: err });
}
```

### Think twice before logging errors

Generally, you should let unexpected errors bubble up to our request middleware, where they’ll be handled and logged. This centralizes error handling and prevents duplicate logs.

Different error types require different treatment.

#### Did it happen because of invalid user input?

Errors caused by invalid input should almost never be logged at the Error level to avoid noise—regardless of whether the bad input came from a user, a frontend bug, or environmental issues (e.g., outdated browser, network changes).

If unexpected input triggers an error in a library, database, or external API, catch it and rethrow a 4xx error (e.g., ValidationFailedProblem) so the middleware does not log it as an error. By default, 4xx errors are not logged by our middleware.

Before throwing a 4xx error, you may log the event at Info or Warn:

* Use Info for anticipated validation failures or common user mistakes.
* Use Warn when the input is unexpected or indicates a potential upstream/client issue.

```tsx
// Don't: log invalid user input as errors.
if (!title) {
	logger.error('Validation failed, title missing')
}

// Don't: throw errors which will be logged as errors by request middleware.
if (!title) {
  throw new Error('Validation failed, title missing')
}

// Do: throw 4xx errors, optionally log as info / warn.
if (!title) {
  logger.info('Validation failed, title missing', { id })
  throw new ValidationFailedProblem({ title: 'Title missing' })
}
```

#### Did it happen in an outgoing request?

Use our Enhanced Fetch library for all API integrations; it provides standardized error handling and logging for outbound requests.

* Don’t catch and log unexpected errors from outbound requests. Let them bubble up to the request middleware for consistent handling and logging.
* Do catch expected outcomes, such as 4xx responses caused by invalid input. When appropriate, use handle204 or handle404 to return null instead. (See the “Invalid user input” section above.)
* Don’t blanket-rethrow all 4xx responses. Some (e.g., 401) may indicate an environment/configuration issue and should bubble up to be handled and logged as unexpected errors.

When you must handle outbound errors to provide a fallback or degraded response, log the original error at the appropriate level:

* Network failures and 5xx responses: log at Error.
* 4xx responses: log at Warn (unless you’ve determined they represent a broader incident, in which case Error is appropriate).

```tsx
// Do: use enhanced fetch which has built-in error handling and logging.
const myFetch = createEnhancedFetch({ name: 'my-integration' })
await myFetch(url)

// Don't: log failed requests. It is done for you in enhanced fetch.
await myFetch.catch(err => {
  logger.error(err)
  throw err
})

// Do: rethrow outgoing request errors related to user input
try {
  await myFetch(url, { body: resource })
} catch (err) {
  if (err.problem?.type === ProblemType.VALIDATION_FAILED) {
	  throw new ValidationFailedError(err.problem.fields, { cause: err })
  }
}

// Do: Log unexpected responses as warnings if you must swallow them.
try {
	return await myFetch(url)
} catch (err) {
  logger.log(err.statusCode < 500 ? 'warn' : 'error', err)
  return fallbackValue
}
```

## **Standard fields**

<table data-header-hidden><thead><tr><th width="136.69140625">Field</th><th width="296.1953125">Description</th><th>Source</th></tr></thead><tbody><tr><td><code>timestamp</code></td><td>Time of the log entry.</td><td>Automatic (Logger)</td></tr><tr><td><code>level</code></td><td>Debug, info, warn or error depending on log method used.</td><td>Manual</td></tr><tr><td><code>message</code></td><td>Concise, human-readable summary of the log entry. The Error message when logging errors.</td><td>Manual</td></tr><tr><td><code>context</code></td><td>Which software component or class the log entry comes from.</td><td>Automatic (Child logger)</td></tr><tr><td><code>codeOwner</code></td><td>The team responsible for this part of our backend architecture.</td><td>Automatic (Service, Endpoint, Resource)</td></tr><tr><td><code>name</code></td><td>The Error name.</td><td>Automatic (Error)</td></tr><tr><td><code>stack</code></td><td>The Error stack trace.</td><td>Automatic (Error)</td></tr><tr><td><code>dd</code></td><td>Extra metadata provided by datadog agent. Includes <code>env</code>, <code>service</code> and <code>version</code> sub fields.</td><td>Automatic (Datadog)</td></tr><tr><td><code>traceSid</code></td><td>Trace Session ID to correlate logs with users without exposing PII.</td><td>Automatic (Authentication)</td></tr><tr><td><code>http</code></td><td>Information about outgoing requests and responses. May include these subfields: <code>status_code</code>, <code>status_text</code> and <code>url</code>.</td><td>Automatic (Enhanced Fetch)</td></tr><tr><td><code>fetch.name</code></td><td>Name of the enhanced fetch integration.</td><td>Automatic (Enhanced Fetch)</td></tr><tr><td><code>organizationSlug</code></td><td>Reference to a government organization which a log entry or error relates to.</td><td>Automatic (Enhanced Fetch)</td></tr></tbody></table>


# Log Requests via Zendesk

### &#x20;Log Requests via Zendesk (Inspection / Review / Extraction)&#x20;

#### Purpose&#x20;

Provide a formal, traceable, and auditable process for log requests. Zendesk is the system of record for intake, approval, execution, and evidence.&#x20;

#### System of Record&#x20;

* Submit requests to: <island@island.is> (creates a Zendesk ticket)&#x20;
* Tickets are routed to a restricted Log Review group&#x20;
* Access: CISO and CTO (and explicitly approved delegates only)&#x20;
* Slack is not an official channel (content can be changed/deleted). Slack may be used only for coordination; decisions/results must be recorded in the ticket.&#x20;

#### Definitions&#x20;

* Log inspection: Confirm if something happened (yes/no, counts, timestamps).&#x20;
* Log review: Analyze events and timeline (explain what happened and why).&#x20;
* Log extraction: Export/share log data (highest risk; requires explicit approval).&#x20;

#### Roles&#x20;

* Requester: Submits request with required details.&#x20;
* Approver (CISO/CTO): Approves/rejects and sets scope/conditions.&#x20;
* Executor (DevOps Engineering / Security): Performs log work and documents actions/results in the ticket.&#x20;
* Ticket Owner: Ensures completeness, tracks progress, ensures approvals and closure notes.&#x20;

#### Request Requirements (must include)&#x20;

* Request type: inspection / review / extraction&#x20;
* Reason / justification&#x20;
* System(s) in scope&#x20;
* Time window (start/end + timezone)&#x20;
* Identifiers (if relevant): request/correlation ID, session ID, user ID, IP, certificate serial, etc.&#x20;
* Requested output (summary, timeline, redacted snippet, export)&#x20;
* Sensitivity (personal data / secrets possible?)&#x20;
* Deadline / urgency&#x20;

If key info is missing, the Ticket Owner requests clarification in the ticket before work begins.&#x20;

#### Approval Rules (CISO/CTO)&#x20;

Approval is required before execution when:&#x20;

* The request involves log extraction/export&#x20;
* Logs may contain personal/sensitive data (including audit logs)&#x20;
* The request relates to security incidents, suspected abuse, fraud, insider concerns&#x20;
* The requester/executor is a solution partner/external team&#x20;
* The scope is broad (e.g., > 7 days, multiple systems)&#x20;

Approvals must be recorded in Zendesk as Approved / Approved with conditions / Rejected.&#x20;

#### Execution Workflow&#x20;

1. Intake: Email to <island@island.is> → Zendesk ticket in restricted group&#x20;
2. Triage: Ticket Owner validates scope/priority and determines if approval is required&#x20;
3. Approve: CISO/CTO approves and defines constraints (scope, timeframe, allowed output)&#x20;
4. Assign (“Tagging”): CISO/CTO tags named individuals or the DevOps group to execute&#x20;
5. Execute: Executor performs log work and records:&#x20;
6. systems accessed, timeframe, query/filters (as appropriate)&#x20;
7. findings summary and limitations (e.g., retention gaps)&#x20;
8. Evidence & Response: Evidence is attached or securely linked; response posted in ticket&#x20;
9. Close: Ticket closed with closure notes (who approved/executed, what was shared, where evidence is stored, completion date)&#x20;

#### Data Handling Rules&#x20;

* Only the restricted group may access these tickets.&#x20;
* Minimize exposure: share only what is necessary to answer the request.&#x20;
* Never share: secrets/tokens/private keys, full auth material, unnecessary personal data.&#x20;
* Raw log exports are only allowed when explicitly approved and necessary.&#x20;
* When personal data is involved, document the lawful basis/justification briefly in the ticket.&#x20;

#### Email Template (Requester)&#x20;

To: <island@island.is> \
Subject: Log Request — \[System] — \[Time window]&#x20;

* Type (inspection/review/extraction):&#x20;
* Reason/justification:&#x20;
* System(s):&#x20;
* Time window (timezone):&#x20;
* Identifiers:&#x20;
* Requested output:&#x20;
* Sensitivity (personal data/secrets possible?):&#x20;
* Deadline/urgency:&#x20;
* Contact person:&#x20;

&#x20;


# Island.is Authentication Service

Digital Iceland has created the Island.is Authentication Service (IAS) as a modern solution to help government organisations authenticate users online. The service is built on open standards including OAuth2 and Open ID Connect and includes scope-based authorisation functionality to support different kinds of delegations as well as user-based API authorisation across organisational boundaries.

Delegations allow individuals to access digital services on behalf of another individual or legal entities. E.g. guardians can access services on behalf of children they ward, and employees can access services on behalf of the company they work for. Note that with delegations, as opposed to impersonation, each delegated access includes cryptographically signed claims about the actual authenticated user.

This documentation is meant for developers and software architects at Service Providers (SPs) planning to integrate with the IAS. It describes the architecture of the authentication service and how to use it.

A full documentation of Open ID Connect (OIDC) and OAuth2 is outside the scope of this documentation. We recommend reading the following resources before integrating with IAS.

* [Open ID Connect](https://openid.net/connect/)
* [OAuth 2](https://oauth.net/2/)

## Table of contents

* [Terminology](/products/auth/terminology)
* [Integration options](/products/auth/integration-options)
* [Authentication flows](/products/auth/authentication-flows)
* [Authorising API endpoints](/products/auth/authorising-apis)
* [Session lifecycle](/products/auth/session-lifecycle)
* [Scopes and tokens](/products/auth/scopes-and-tokens)
* [Delegations](/products/auth/delegations)
* [Configuration](/products/auth/configuration)
* [Tools and examples](/products/auth/integration-guidance)
* [Environments](/products/auth/environments)
* [Test IAS with Postman](/products/auth/postman-test)


# Terminology

## Requirements Notation

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this documentation are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).

## Terms

The IAS documentation uses the following terms:

**Access Token**

Access tokens are Credentials used to access protected resources. Access tokens issued by IAS are [**JSON Web Tokens (JWTs)**](https://openid.net/specs/openid-connect-core-1_0.html#JWT) signed with the [RS256 algorithm](https://datatracker.ietf.org/doc/html/rfc7518#section-3).

**Claim**

Piece of information asserted about an Entity.

**Client**

An application making protected resource requests on behalf of a resource owner (such as a user).

**Credential**

Data presented as evidence of the right to use an identity or other resources.

**End-User**

Human participant.

**Entity**

Something that has a separate and distinct existence and that can be identified in a context. An End-User is one example of an Entity.

**ID Token**

[**JWT**](https://openid.net/specs/openid-connect-core-1_0.html#JWT) that contains Claims about an Authentication. It MAY contain other Claims.

**Issuer**

Entity that issues a set of Claims.

**JSON Web Token (JWT)**

JSON Web Token (JWT) is a compact, URL-safe means of representing Claims to be transferred between two parties.

**Refresh Token**

Refresh tokens are Credentials used to obtain Access Tokens.

**Resource Owner**

An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an End-User.

**Resource Server**

A server hosting protected resources, usually in the form of an API. Capable of accepting and responding to protected resource requests using Access Tokens.


# Integration Options

There are many ways to integrate your application with IAS, depending on your needs.

## User authentication only

If your app only needs to call your own APIs and they can share a session cookie for authorization, you CAN use IAS to authenticate the user only.

In this case you MUST use the Authorization Code + PKCE flow to authenticate the user.

Using OIDC you can authenticate the user and get claims (like `name` and `nationalId`) about them from the ID token or the UserInfo API endpoint. In your authorization callback you can link the user claims to your own resources, create a session cookie and use it to authorise calls to your API.

This has many benefits:

* You don’t need to manage Access Tokens and Refresh Tokens, which reduces potential attack surface significantly.
* You don’t need to keep track of multiple session lifecycles (cookies, access token, refresh token).
* Session security, CSRF and authorization are commonly built into frameworks, while OAuth2 logic often needs to be written or tweaked by hand.

The drawbacks are:

* You can’t call APIs which are authorised with IAS access token.
* It’s more difficult to authorise APIs that are on separate domains and can’t share a session cookie.

## User authentication and API authorization

In some cases you need an IAS Access Token to access user resources from APIs. These APIs might belong to another organisation (on another domain) or they might be your own APIs which you want to authorise with IAS rather than a session cookie. In this case you MUST use a confidential client and the Authorization Code + PKCE flow.

Special care is needed to protect Access Tokens since they may grant access to sensitive user resources.

Access Tokens issued by IAS have a short lifetime; no more than 5 minutes in production. To support longer user sessions you SHOULD request a Refresh Token and use it to refresh Access Tokens when they expire.

You SHOULD NOT store tokens [in browser storage or even browser memory](https://medium.com/@benjamin.botto/secure-access-token-storage-with-single-page-applications-part-1-9536b0021321), as that will expose them to XSS attacks and token exfiltration. Leaked tokens can be more serious than normal XSS attacks since tokens sometimes provide a wider access to user resources then your application exposes.

Instead, you SHOULD keep tokens in a secure backend session storage.

## Client authentication for APIs

Some apps need to access APIs when no user is around, e.g. from queue workers or cron jobs.

If you are performing offline processing for a user that has previously authenticated to your application you should consider storing the user’s Refresh Token so you can get a fresh Access Token when you need to perform the offline processing. This is preferable to Client Credentials since each access is limited to previously authenticated users which have presumably given consent for the access.

However, in some cases you may not have a user authentication to use or you need access to resources which the user does not own. In that case you SHOULD use Client Credentials to authenticate your system as a client.

Bear in mind that with Client Credentials, the client is considered the resource owner. You SHOULD take special care to protect the client credentials and limit the scopes which the client has access to.


# Authentication Flows

Now that we’ve reviewed some of the ways you can integrate IAS, let’s dive into the supported authentication flows.

## Authorization Code + PKCE

If you are creating a Mobile App or Website you SHOULD authenticate using the Authorization Code flow with Proof Key for Code Exchange (PKCE).

This flow is secure from multiple kinds of attacks when implemented correctly.

![Authorization Code + PKCE Flow](/files/WnIv6fJ62jeEqojAMd0x)

The Authorization Code + PKCE Flow goes through the following steps.

1. The user clicks the “Login” link in your application.
2. Your app creates a cryptographically-random Code Verifier which is used to generate a Code Challenge. These two values are needed for the PKCE validation.
3. Your app redirects the user to IAS’s `/connect/authorize` endpoint, with Response Type and Code Challenge parameters in the query string to indicate to the IAS the usage of Authorization Code + PKCE flow.
4. The IAS shows a login screen to the user.
5. The user authenticates to IAS using Auðkenni.
6. IAS stores the Code Challenge and redirects the user back to your application with a single-use Authorization Code.
7. Your app sends the Authorization Code and the Code Verifier to IAS’s `/connect/token` endpoint.
8. IAS verifies the Code Challenge and Code Verifier.
9. IAS returns an ID Token, an Access Token and optionally a Refresh Token.
10. The App can use the Access Token to call Your API to access information about the user.
11. Your API validates the Access Token and responds with requested data.

### Library Configuration

Using an OIDC library, you need the following parameters to perform a user authentication:

* `Client ID` to authenticate your client. You get this from IAS.
* `Client Secret` if your client is confidential. You get this from IAS.
* `Scope` is a space-separated list of scopes which grants access to specific APIs using the access token or claims in the ID token. You can only list scopes which your client has access to.
* `Redirect Uri` specifies where IAS should redirect to after authenticating the user. This MUST match your client configuration in IAS.
* If your library supports OIDC discovery:
  * `Issuer` or `Authority`, the base URL of IAS (see below).
* Otherwise:
  * `Authorization Endpoint`, for IAS this is `${Issuer}/connect/authorize`
  * `Token Endpoint`, for IAS this is `${Issuer}/connect/token`

## Client Credentials

With Client Credentials, the API only authenticates the client performing the request.

![Client Credentials Flow](/files/hRi5N6Bhbobk5uAqYHil)

The Client Credentials Flow goes through the following steps.

1. Your app sends its Client ID and Client Secret to IAS’s `/connect/token` endpoint to authenticate.
2. IAS validates the Client ID and Client Secret.
3. IAS returns an Access Token.
4. The App can use the Access Token to call the API.
5. The API validates the Access Token and responds with requested data.

### Library Configuration

You need the following parameters to perform a client authentication:

* `Client ID` and `Client Secret` to authenticate your client. You get this from IAS.
* `Scope` is a space-separated list of scopes which grant access to specific APIs. You can only list scopes which your client has access to.
* If your library supports OIDC discovery:
  * `Issuer` or `Authority`, the base URL of IAS (see below).
* Otherwise:
  * `Token Endpoint`, for IAS this is `${Issuer}/connect/token`


# Authorising API Endpoints

Tokens issued by IAS are [JSON Web Tokens (JWT)](https://datatracker.ietf.org/doc/html/rfc7519) which are cryptographically signed to prevent tampering.

If you are creating a Resource Server that accepts Access Tokens issued by IAS you MUST validate tokens properly:

<figure><img src="/files/a7B9TOnllyIjojBIAmD6" alt=""><figcaption><p>Authorising APIs Flow</p></figcaption></figure>

1. The Client calls the Resource Server with an Authorization header containing a bearer JWT Access Token issued by IAS.
2. The Resource Server checks if it has a cached RSA public key matching the incoming Access Token. If not, it requests a JSON Web Key Set (JWKS) from IAS.
3. IAS returns all of the public keys for its tokens in a JWKS response.
4. The Resource Server MUST validate the signature of the Access Token JWT using the RSA public key from the JWKS.
5. The Resource Server MUST validate Access Token Claims to see if it was issued (”iss”) by IAS, that it is valid (”nbf” and ”exp”) and at least one Resource Server's scope is listed in the token’s "scope" claim.
6. The Resource Server MAY further authorise the requested resources based on Claims from the Access Token, eg “scope” and “nationalId”.
7. The Resource Server returns the requested Resources.

### Library Configuration

Authorisation libraries often support the following parameters to validate bearer tokens:

* `Scope` which scope is required to call the endpoint.
* `Issuer` or `Authority`, the base URL of IAS (see below).
* If your library does not supports OIDC discovery:
  * `JWKS Endpoint`, for IAS this is `${Issuer}/.well-known/openid-configuration/jwks`


# Session Lifecycle

When users sign into applications there are up to 3 sessions to be aware of. These sessions are independent but this chapter explains some ways to keep them in sync.

![](/files/tHZuPh4nubOKiJmQw2nX)

## Token Session

For applications which use IAS Access Tokens, you need to consider the token lifecycle.

Access Tokens by default last 5 minutes. They can’t be invalidated, so care should be made to protect access tokens and remove them as soon as the user logs out.

With Refresh Tokens your app can get new Access Tokens as they expire. IAS supports both Inactive Lifetime and Absolute Lifetime for Refresh Tokens. These specify how much time can pass between the app refreshing tokens, as well as the total amount of time the app can refresh tokens.

For sensitive applications it makes sense to have the Refresh Token expirations fairly short (eg 30 minutes inactive, 8 hours absolute). For native applications or less sensitive applications these can be longer (weeks or months).

See [Refresh Token Expiration](/products/auth/scopes-and-tokens#refresh-token-expiration) for more explanation of absolute and inactive lifetimes.

#### Default Recommended Refresh Token Lifetimes

<table><thead><tr><th></th><th width="169">web</th><th width="159">native</th></tr></thead><tbody><tr><td>Inactivity Lifetime</td><td>20 minutes</td><td>90 days</td></tr><tr><td>Absolute Lifetime</td><td>8 hours</td><td>1 year</td></tr></tbody></table>

{% hint style="info" %}
`machine` clients SHALL NOT use refresh token, as they MUST request new access token using their `clientId` and `secret`, when it expires.
{% endhint %}

When the user logs out of your application, you should revoke the refresh tokens using IAS’s [`revocation_endpoint`](https://datatracker.ietf.org/doc/html/rfc7009) so the refresh tokens can’t be used again. The endpoint is listed in the [`.well-known/openid-configuration`](https://innskra.island.is/.well-known/openid-configuration) document.

{% hint style="danger" %}
If a token refresh fails, it indicates that the Refresh Token has expired, been revoked or used elsewhere (stolen refresh token). In this case you should sign the user out of your application immediately.
{% endhint %}

#### Token lifetimes and delegations

If your client supports delegations it's important to understand how token lifetimes influence delegation behaviour.  The Absolute Lifetime and, if defined, the Inactive Lifetime determine how long the user can continue to switch between delegations without needing to re-authenticate.

* By default, the Absolute Lifetime sets the maximum duration for delegation use.
* If an Inactive Lifetime is configured, it will take precedence—meaning the user must be actively using the application to continue switching delegations. If no activity is detected within that time window, re-authentication is required, even if the Absolute Lifetime hasn't been reached.

## Application Session

Many application frameworks have their own session system, i.e. using cookies. These sessions have their own lifecycles separate from Tokens and IAS.

If your application logic depends on IAS Access Token, then you may want to configure your Application Session to outlive the Token Session and/or sync the two:

* If the user signs out, clear your application session in addition to revoking the Refresh Token.
* If the Token Session expires, then clear your Application Session cookie before signing the user out.

## IAS Session

IAS has its own session, this provides the option of a Single Sign-On experience. Currently SSO is enabled for all clients. SSO will be disabled by default and configured in the IDS Admin portal, see documentation [here](/products/auth/using-the-ias-admin-portal#configuring-single-sign-on-sso).&#x20;

SSO makes it so the user can quickly authenticate to different clients. The IAS Session lasts for 60 minutes after each authentication but no longer than 8 hours. This means that if you link your user to another application which uses IAS, and it’s been less than 60 minutes since they first logged in, they won’t need to authenticate again. They’ll immediately be authenticated to the second application. Then if they go back to your application or a third application within 60 minutes of that, they still won’t see a sign-in screen.

If you have SSO enabled but wish to force a re-authentication from your users you can use the `prompt=login` parameter. You can then use the `auth_time` claim to verify that the authentication used to generate the token is indeed fresh. You can read more about forcing re-authentication [here](https://auth0.com/docs/authenticate/login/max-age-reauthentication)

If the user logs out of your application, you SHOULD perform an [RP Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout) to terminate the IAS Session.

Even though the user signs out of another application and ends the IAS Session, your application might still have a valid Token Session for some time. IAS does not guarantee single sign-out.


# Scopes and Tokens

## IAS Scopes

IAS has built-in scopes which provide access to user claims in the ID token and in the IAS userinfo endpoint.

### `openid`

Standard scope REQUIRED for user authentication with Open ID Connect. Returns the following claims:

* `sub` - Uniquely identifies the subject. When using delegations it uniquely identifies the subject+actor.
  * I.e. when users A and B act as user C, they have different `sub` values from each other, which is also different from user A, B and C’s normal `sub` values.
* `subjectType` - The user-type of the subject. Can contain values:
  * `person` - The subject is a person.
  * `legalEntity` - The subject is a legal entity.
* `nationalId` - The nationalId of the subject. If the user has chosen to act in a delegation, then this is the nationalId of the chosen delegation, otherwise it’s the nationalId of the authenticated user.
* `actor` - Information about the authenticated user. Only available when a delegation is active. Contains nested claims:
  * `nationalId` - The nationalId of the authenticated user.
  * `name` - Full name of the authenticated user.

### `profile`

Request user profile-related information claims:

* `name` - Full name of the user.
  * For individuals, this comes from National Registry’s Einstaklingar API, falling back to the name saved on the Electronic ID used to authenticate.
  * For companies, this comes from Skattur’s Company Registry API.

### `email`

Request user profile primary email claim:

* `email` - Primary email of the user in user-profile service.
* `email_verified` - Boolean indicating if the email is verified by two-factor code.

### `phone`

Request user profile phone claim:

* `phone_number`  - Phone number of the user from the user-profile service.
* `phone_number_verified`  - Boolean indicating if the phone number is verified by SMS code.
* `audkenni_sim_number` - If the user authenticated using eID on SIM this is the phone number from the SIM.

### `address`

User's address from National Registry (ísl. aðsetur).

* `address`  - Address object with the following properties:
  * `formatted` - Formatted address string as\
    \&#xNAN;*street\_address*\
    *postal\_code locality*\
    *country*
  * `street_address`&#x20;
  * `locality`
  * `region`
  * `postal_code`
  * `country`

### `offline_access`

Request a Refresh Token with other tokens, which can be used to request new Access Tokens.&#x20;

{% hint style="info" %}
Your Client needs to be configured to allow offline access to receive Refresh Tokens.
{% endhint %}

## Access Tokens

Access Tokens issued by the IAS are JWT bearer tokens signed using RSA keys. This allows Resource Servers to validate Access Tokens and extract claims without calling the IAS introspection endpoint for every request.

This decentralised design has clear benefits when it comes to performance, scaling and reliability, but it also means that it’s impossible to revoke Access Tokens after they’ve been issued. When the user signs out, there might be an Access Token somewhere which can still be used.

To minimise the impact of this risk, IAS issues Access Tokens with an expiry of 5 minutes or less.

If your client needs to access Resource Servers for a longer time they can use Refresh Tokens to request new Access Tokens.

## Refresh Tokens

Refresh Tokens issued by IAS are configured with Refresh Token rotation. This means that each time you use your Refresh Token to request a new Access Token, you also get a new Refresh Token.

![Refresh Token flow](/files/GLVs143S652aQmOz4hGb)

1. When a client needs to access an API and its Access Token is expired, it performs a Token Refresh to get a new Access Token. It sends its Refresh Token (RT1) to the IAS Token Endpoint with `grant_type=refresh_token`. Confidential clients also pass their Client ID and Client Secret to authenticate.
2. The IAS validates RT1, checks if it has expired, been used before or otherwise revoked.
3. If RT1 is valid, IAS issues a new tokens AT2 and RT2 and returns them to the client.
4. The client uses the new AT2 to request data from the API.
5. The API sees that AT2 is valid and returns resources.

Behind the scenes, each authentication forms a chain of Refresh Tokens. If the same Refresh Token is used to request an Access Token for a second time, that request will fail and IAS will revoke that complete chain of Refresh Tokens. The user is forced to re-authenticate.

This means that if an adversary gets access to a Refresh Token in any way, that access will be blocked, either immediately, or the next time the real Client refreshes its token. The real user will notice this by the fact that they’ve been signed out.

![Refresh Token Leak](/files/pkslFdQsIoBYY4CfrrT5)

### Protecting Refresh Tokens

You MUST protect Refresh Tokens carefully since they can be used to generate new Access Tokens without user intervention. Refresh Tokens SHOULD never be accessible to client side code which is susceptible to Cross Site Scripting (XSS) attacks.

We RECOMMEND storing Refresh Tokens in secure database storage. If you need to store it in a cookie-based session, the cookie should be configured with HTTPOnly, Secure and SameSite flags to limit access to it, and its contents should ideally be encrypted.

### Refresh Token expiration

You can configure Refresh Token expiration settings based on the needs of your Client. These settings form the basis of how long a specific authentication can be used to access user resources from Resource Servers.

For interactive clients that depend on user data from Resource Servers, the lifetime of Refresh Tokens SHOULD decide the lifetime of the user session. If requesting a new Access Token using a Refresh Token fails because of an expired or revoked Refresh Token, you can clear the user session and sign the user out.

You can configure both absolute expiration and inactive expiration.

**Absolute Expiration** specifies the absolute lifetime of all Refresh Tokens from a single authentication event.

![Absolute Expiration graphic](/files/fLxE8ZEhwDAYvtcD6iTx)

**Inactive Expiration** specifies the maximum lifetime of each individual Refresh Token in seconds. If the user is inactive and your client doesn’t use the latest Refresh Token for this amount of time, then the Refresh Token expires and can’t be used to issue new Access Tokens.

![Inactive Expiration graphic](/files/KjH0uDfzidvs3pMwnV87)


# Delegations

IAS includes a delegation system which allows individuals and organisations to grant others access to digital services on their behalf. For example, guardians can sign in on behalf of their wards, and employees can sign in on behalf of the company they work for.

In addition to explicit delegation grants (where identity A creates delegation grants for user B), we support implicit delegation grants from external delegation registries. We currently support these kinds of implicit delegations:

* Legal guardians for underage users. (Source: Þjóðskrá)
* Procuring holders for companies. (Source: Fyrirtækjaskrá)
* Personal representatives for represented users. (Source: Talsmannagrunnur)

## Delegation configuration

Clients can configure what kinds of delegations they support. This controls which delegations the user can choose when authenticating with the client.

Scopes configure what kind of delegations the respective API supports. It affects which API scopes can be added to access tokens when acting in a delegation.

## Switching delegations

When a user signs into a client which supports delegations, IAS prompts the user with a choice to authenticate without a delegation, or authenticate with a specific delegation.

## Delegated tokens

Delegations are reflected in the ID and Access Tokens, where the chosen identity becomes the subject of the token and the authenticated user is the `actor`.

Example Access Token for a delegation (trimmed):

![](/files/gix1rmoowxa181jrWsbn)

This design reduces the information shared with the client. The client only sees the delegations which the user chooses.

It also means resource servers can easily validate access tokens and return resources for the chosen delegation.

To prevent impersonation attacks, resource servers MUST validate the scope claims. If they support delegations they SHOULD also audit both identities from the token.

## Delegation types

The `delegationType` property in the ID and Access tokens indicates what kind of delegation the token represents. It is an array of strings, as delegation can be merged. For example a legal guardian can also have a custom delegation from its child. The property can contain the following values:

* `LegalGuardian` - Legal guardian of a underage user based on National Registry.
* `ProcuringHolder` - Procuring holder of a company based on Company Registry.
* `PersonalRepresentative` - Personal representative of a represented person based on Félags- og vinnumarkaðsráðuneytið.
* `Custom` - Explicit delegation created by the user in island.is delegation system.

## Audit Requirements

SPs which integrate with delegations SHOULD keep an audit log which tracks both subject and actor identities.

We RECOMMEND including these fields in your audit log:

* `subject` - The national id of the active identity from the access token. Can be the authenticated user, a company or another person. This can be `national_id` claim.
* `actor` - The national id of the authenticated user. This is the `actor.national_id` claim if the `actor` claim is defined, otherwise it is the root `national_id` claim, same as the subject.
* `client` - IAS clients involved with the request. This SHOULD be an array to audit a chain of clients using token exchange.


# Configuration

IAS has an admin interface which can be used to define new Clients(applications) and Scopes(permissions). An organisation can request access to this admin interface by contacting island.is and then grant developers access on behalf of the organisation.

## Configuring IAS organisation

Organisations in IAS serve as containers for clients and scopes. They have these fields:

* **National ID:** The national ID of the organisation.
* **Domain:** The primary domain for the organisation, used as a prefix in client, resource and scope names; e.g. `island.is`.
* **Contact Email:** Email which Digital Iceland can use for service notifications and issues.

## Defining clients

When defining clients, you need to provide the following:

* **Client Type:** Web Client, Native Client (for mobile apps) or Machine Client (client credentials).
* **Client ID:** Should follow naming convention `@{domain}/{clientName}`
* **Client Secret:** Required for web and machine clients.
* **Display Name:** What the user sees when logging into your application.
* **Supported Delegations:** What kind of delegations to support (Legal Guardian, Personal Representative, Procuring Holders, Custom).
* **Prompt Delegations:** Determines if users will be prompted to choose a delegation when signing into your app.
* **Allow Offline Access:** Should the client be able to get refresh tokens.
* **Refresh Token Expiration:** Inactive vs Absolute expiration of refresh tokens in seconds.
* **Redirect Uri:** Which callback URIs should be allowed when logging in with this client. In the staging environment you can use wildcard tokens (`*`) to support feature deployed subdomains, e.g. `https://*.dev.yourapp.com/oauth/callback`.
* **Post Logout Uri:** Which URIs should be allowed when logging out of this client.
* **Identity Providers:** Specifies which [Identity Providers](#supported-identity-providers) to be used when authenticating to this client.
* **Grant Types:** What kind of authentication flow the client will use. Authorization Code for web and native clients. Client Credentials for machine clients and optionally allow for token exchange.
* **Scopes:** Which scopes should the client be able to request.

### Supported identity providers

IAS currently supports three identity providers, all of which provide a high level of assurance with digital certificates issued to hardware devices in-person.

Clients can configure which identity providers they want to support:

#### SIM Card

This uses electronic ID saved on SIM cards in mobile phones.

#### Identity Card

The Identity Cards look like credit cards and have electronic IDs saved on them. They require a dedicated card reader to use.

#### Mobile App

The newest Identity Provider is a mobile app called Auðkennisappið where the electronic ID is saved in secure device storage.

## Defining scopes

If you want to use IAS access tokens to authorise requests to your APIs you must define one or more scopes for the API’s endpoints.

### Scope configuration:

* **Name:** Should follow naming convention `@{domain}/{scopeName}`
* **Display Name:** Shown on consent screen.
* **Description:** Shown on consent screen.
* **Supported delegations:** What kind of delegations can use this scope (Legal Guardian, Personal Representative, Procuring Holders, Custom).
* **Personal Representative Permissions:** Which personal representative permissions, if any, gives access to this scope.
* **Claims:** Which user claims do the API endpoints need in the access token (e.g. `nationalId`).

## Example

Let's say your organisation's domain is `myorg.is`, with a web app on `app.myorg.is` which uses IAS to authenticate normal users and needs an access token to talk to a "Document API" hosted on `documents.myorg.is`.

You can create the following IAS resources:

### Webapp client

* **Client Type:** Web Client
* **Client ID:** `@myorg.is/webapp`
* **Client Secret:** XXX...
* **Display Name:** My Org Webapp
* **Supported Delegations:** None
* **Prompt Delegations:** No
* **Allow Offline Access:** Yes
* **Refresh Token Expiration:** 30m inactive, 24h absolute
* **Redirect Uri:** `https://app.myorg.is/oauth/callback`
* **Post Logout Uri:** `https://myorg.is`
* **Identity Providers:** All
* **Grant Types:** Authorization Code
* **Scopes:** `@myorg.is/documents:read` and `@myorg.is/documents:write`

### Document API's read documents scope

* **Name:** `@myorg.is/documents:read`
* **Display Name:** Read documents
* **Description:** Read access to the user's documents.
* **Supported delegations:** None
* **Claims:** `nationalId`

### Document API's write documents scope

* **Name:** `@myorg.is/documents:write`
* **Display Name:** Write documents
* **Description:** Read/Write access to the user's documents.
* **Supported delegations:** None
* **Claims:** `nationalId`

{% hint style="info" %}
Even though the `name` field of clients and scopes have the same naming convention, they won't conflict with each other and there's no associations based on the name.
{% endhint %}

### Example authentication

1. User goes to `https://app.myorg.is` which has the `@myorg.is/webapp` client.
2. The user clicks a login button. The client sends them to the IAS authorize endpoint: `https://innskra.island.is/connect/authorize` with these query parameters:
   * client\_id=@myorg.is/webapp
   * redirect\_uri=<https://app.myorg.is/oauth/callback>
   * response\_type=code
   * scope=openid profile offline\_access @myorg.is/documents:read @myorg.is/documents:write
   * state={SOME\_STATE}
   * code\_challenge={CODE\_CHALLENGE}
   * code\_challenge\_method=S256
   * response\_mode=query
3. The user authenticates and IAS sends the user to the client callback URL: `https://app.myorg.is/oauth/callback` with these query parameters:
   * code={AUTHORIZATION\_CODE}
   * scope=openid profile offline\_access @myorg.is/documents:read @myorg.is/documents:write
   * state=SOME\_STATE
4. The client performs a POST request to the IAS token endpoint: `https://innskra.island.is/connect/token` with the following payload encoded as `content-type: application/x-www-form-urlencoded`:
   * client\_id=@myorg.is/webapp
   * client\_secret=XXX...
   * code={AUTHORIZATION\_CODE}
   * redirect\_uri=<https://app.myorg.is/oauth/callback>
   * code\_verifier={CODE\_VERIFIER}
   * grant\_type=authorization\_code
5. The client receives the ID token, access token and refresh token in the response:

   ```json
   {
     "id_token": "{idToken}",
     "access_token": "{accessToken}",
     "refresh_token": "{refreshToken}",
     "expires_in": 300,
     "token_type": "Bearer",
     "scope": "openid profile offline_access @myorg.is/documents:read @myorg.is/documents:write"
   }
   ```
6. The client can decode the ID token or call the userinfo endpoint: `https://innskra.island.is/connect/userinfo` with the access token to get authentication claims:

   ```
   {
     "sub": "{subject}",
     "nationalId": "{userNationalId}",
     "subjectType": "person",
     "name": "{userFullName}",
     
     // Additional when delegation
     "delegationType": [
       "Custom"
     ],
     "actor": {
       "nationalId": "{userNationalId}",
       "name": "{userFullName}"
     },
   }
   ```
7. The client can use the access token to call the documents API: `https://app.myorg.is/documents`. When decoded and validated the access token also contains claims about the authenticated user:

   ```json
   {
     "nbf": { notValidBeforeTime },
     "exp": { expiryTime },
     "iat": { issuedAtTime },
     "auth_time": { authenticationTime },
     "iss": "https://innskra.island.is",
     "client_id": "@myorg.is/webapp",
     "sub": "{subject}",
     "idp": "{identityProvider}",
     "nationalId": "{userNationalId}",
     "jti": "{tokenId}",
     "sid": "{sessionId}",
     "scope": "openid profile offline_access @myorg.is/documents:read @myorg.is/documents:write",
     "amr": [{authenticationMethod}],
     "acr": "eidas-loa-high"
   }
   ```

### Example sign-out

1. User is using the site `https://app.myorg.is` which has the `@myorg.is/webapp` client.
2. The user clicks a logout button. The client redirects them to the IAS `/endsession` endpoint: `https://innskra.island.is/connect/endsession` with these query parameters:

   * id\_token\_hint={YOUR\_ID\_TOKEN}
   * post\_logout\_redirect\_uri=[https://app.myorg.is](https://app.myorg.is/)

   See additional support query parameters in the [OpenID Connect RP Initiated Logout Specification](https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout).
3. If the `post_logout_redirect_uri` is valid, IAS redirects the user back to the client using that URI.


# Tools and Examples

Authentication is a security critical part of applications, SPs SHOULD implement it with high-quality OIDC libraries rather than implementing OIDC from scratch.

## Tools

We recommend these libraries and frameworks to integrate OIDC:

**Authentication**

* [NextAuth.js](https://next-auth.js.org/) - Authentication for Next.js projects.
* [node-openid-client](https://github.com/panva/node-openid-client) - OIDC implementation for Node.js.
* [AppAuth](https://appauth.io/) - OIDC implementation for mobile apps: [iOS](https://github.com/openid/AppAuth-iOS), [Android](https://github.com/openid/AppAuth-Android), [JS](https://github.com/openid/AppAuth-JS), [React Native](https://formidable.com/open-source/react-native-app-auth/) and [Flutter](https://pub.dev/packages/flutter_appauth).
* [ASP.NET Core Authentication](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/secure-net-microservices-web-applications/#authenticate-with-an-openid-connect-or-oauth-20-identity-provider) - OIDC implementation for .NET.
* [Nimbus OAuth + OIDC SDK](https://connect2id.com/products/nimbus-oauth-openid-connect-sdk) - OIDC implementation for Java Applications.

**Validating access tokens**

* [Nimbus JOSE + JWT](https://connect2id.com/products/nimbus-jose-jwt) - JWT validation for Java.
* [passport-jwt](http://www.passportjs.org/packages/passport-jwt/) + [jwks-rsa](https://github.com/auth0/node-jwks-rsa) - JWT validation for Node.js.
* [ASP.NET Core Authentication](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/secure-net-microservices-web-applications/#consume-security-tokens) - JWT validation for .NET.

## Examples

We have a few sample integration projects showing how to connect to the authentication system in various languages and platforms.

{% hint style="info" %}
For now, these examples are in a private repo and only available to our early integration partners.
{% endhint %}

### **NestJS:**

There are two different **NestJS** services which use IAS.

1. [A service](https://github.com/island-is/identity-server.samples/tree/feature/adding-sample-projects/demo-apis/NestDemoApi) with a "JWT" auth-guard that can be added as a guard to controllers or functions, meaning that it’s only possible for tokens issued by IAS with a specific scope to call those controllers or functions. It includes an OpenApi schema and Swagger configuration so that you can authenticate with IAS and call the service endpoints directly from Swagger.
2. [A service](https://github.com/island-is/identity-server.samples/tree/feature/adding-sample-projects/nestjs) which calls another service using IAS access tokens. The purpose of this example is to show how to use Client Credentials to get an Access Token from IAS in NestJS.

### **.NET**

We implemented two different .NET services which use IAS.

1. [A service](https://github.com/island-is/identity-server.samples/tree/feature/adding-sample-projects/demo-apis/NetCoreDemoApi) which authorises Access Tokens from IAS, meaning that it requires tokens issued by IAS with a specific scope to call the controllers or functions in the service marked with the `Authorization` flag. It includes an OpenApi schema and Swagger configuration so that you can authenticate with IAS and call the service endpoints directly from Swagger.
2. [A service](https://github.com/island-is/identity-server.samples/tree/feature/adding-sample-projects/netCore) which calls another service using IAS access tokens. The purpose of this example is to show how to use Client Credentials to get an Access Token from IAS in NestJS.

### Next.js

A next.js [example](https://github.com/island-is/identity-server.samples/tree/feature/adding-sample-projects/nextjs) that demonstrates how you can generate and use the token from IAS. It also demonstrates how you can use that token to call a function in one of the demo services above.

## Postman

Check out [our article](/products/auth/postman-test) on how to configure Postman to authenticate with IAS.


# Environments

The IAS has the three environments but SPs SHOULD generally only integrate with the production and staging environments.

You should only need the issuer URI (sometimes called authority) for your integration, everything else can be configured automatically with Open ID Discovery. If you need to find other endpoints (eg authorization, token, userinfo and jwks) you can find them in the OpenID Configuration.

## Production

> **Issuer:** <https://innskra.island.is/>
>
> **OpenID Configuration:** <https://innskra.island.is/.well-known/openid-configuration>
>
> **Users:** Real

The production environment is meant for SPs in production. It does not authenticate fake users.

## Staging

> **Issuer:** <https://identity-server.staging01.devland.is/>
>
> **OpenID Configuration:** <https://identity-server.staging01.devland.is/.well-known/openid-configuration>
>
> **Users:** Real and fake

The staging environment SHOULD be used when developing and testing an IAS integration.

## Development

> **Issuer:** <https://identity-server.dev01.devland.is/>
>
> **OpenID Configuration:** <https://identity-server.dev01.devland.is/.well-known/openid-configuration>
>
> **Users:** Real and fake

The development environment is used internally at [Island.is](http://Island.is) to develop and test new functionality.

{% hint style="info" %}
SPs SHOULD NOT integrate with the development environment directly. Your development environment SHOULD integrate with the staging environment of IAS instead.
{% endhint %}

## Fake users

In the development and staging environments you can authenticate into your client as fake users (Gervimenn). These can be useful to test different delegation scenarios.

You can request authentication details for fake users from <island@island.is>.

{% hint style="warning" %}
There is no two-factor authentication for fake users. This means anyone can authenticate and impersonate them. Depending on your App, you might need to host your dev/staging environments on internal networks, add secondary authentication or limit what users can do in these environments.
{% endhint %}


# Test IAS with Postman

Here is a guide on how you can verify and test your client configuration using [Postman](https://www.postman.com/).

{% hint style="info" %}
Before you start, download our example Postman collection

{% file src="/files/enucSfN84ZaEIyhpKfLm" %}
Example Postman Collection
{% endfile %}
{% endhint %}

## Step 1 - Navigate to the collection settings

After you have imported the example collection click the collection name in the collection list to open the settings.

![Step1](/files/6cII03p5s3oKJTnTzuVV)

## Step 2 - Fill in your variables details

Next you need to fill in your client specific details in the collection variables. Click the *Variables* tab and fill in the following details and remember to save:

* `CLIENT_ID`
* `CLIENT_SECRET`
* `REDIRECT_URI`

{% hint style="info" %}
If you are using Postman Cloud to sync your work or share with your teammates you should protect your `CLIENT_SECRET`. By only setting the **CURRENT VALUE** the value is not synchronized to Postman's cloud.
{% endhint %}

![Step2](/files/vombXFlmbVDOKRgQOr8R)

{% hint style="warning" %}
Remember to save your collection when you have updated the values.
{% endhint %}

## Step 3 - Get New Access Token

Now you should be able to get new access token in Postman. Click the *Authorization* tab to open the authorization view. Everything should be configured using the variables.

Here you can update the *Scope* input if you want to test the client access to some specific scopes, but you should always include the `openid` and `profile` scopes. For example to test if the client is configured for offline access you could add the `offline_access` scope so the value would be `openid profile offline_access`.

{% hint style="info" %}
We recommend to use [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) even though you are using confidential client with secret. The PKCE improves security to prevent CSRF and authorization code injection attacks.
{% endhint %}

![Step3](/files/8icXjw9A4wYlxv7CNcAE)

## Step 4 - Authenticate

After clicking the `Get New Access Token` button Postman opens a dialog. If the client configuration is valid you should see the login screen where you can log in.

If you see some error message check out the [Troubleshooting](#troubleshooting) section for more details.

![Step4](/files/RbXXtRu9IIYyR5CJpDdO)

## Step 5 - Receive tokens

If you authenticate successfully you should see the *Manage Access Tokens* dialog with your new tokens 🎉\
You can use <https://jwt.io/> to decode the tokens and view which claims it contains.

![Step5](/files/3buDgxubZkkdcQOpI81P)

## 🐞 Troubleshooting

Here are the most common errors when testing the client configuration

### invalid\_request - Invalid Redirect URI

When you see the message `invalid_request` the most common cause is the *Redirect URI* provided is not registered as an allowed URI in the client defintion in the IAS.

You can edit the list of allowed URIs in the IAS admin portal under Application>Application URLs>Callback URL

{% hint style="warning" %}
The *Redirect URI* is case sensitive and sensitive for trailing slash.
{% endhint %}

![InvalidRedirectUri](/files/GnDC7JwrIlAWWAfHD0NH)

### invalid\_scope - Invalid Client Scope

When you see the message `invalid_scope` one or more scopes in the *Scope* input does either not exists or the client has not yet been granted access to some scopes.

You can view and edit the list of scopes granted to a client in the IAS admin portal under Application>Permissions.

![InvalidScope](/files/6bx3hGMPG49t4IGFNZbT)

### unauthorized\_client - Invalid Client ID

When you see the message `unauthorized_client` the most common cause is that the *Client ID* is invalid.

Please verify that your configured *Client ID* is matching the *Client ID* shown in the IAS admin portal and make sure that you are connecting to the correct IAS environment.

![InvalidClientId](/files/GGoHOorQA46QySjviFEk)

### Authentication failed - Invalid Client Secret

When you see a error message from Postman that the authentication failed and you find the message `Error: invalid_client` in the Postman Console the most common cause is the *Client Secret* is invalid.

Please verify that your configured *Client Secret* is matching the *Client Secret* shown in the IAS admin porta&#x6C;*.* Note that postman does not url encode client secrets before sending them so try manually url encoding your secret before entering it into Postman.&#x20;

![InvalidClientSecret](/files/TsQFvvM6oh6pufbwew8w)


# Using the IAS admin portal

Public institutions and municipalities who use the IAS are granted access to an admin portal accessible at <https://island.is/stjornbord/innskraningarkerfi>. The admin portal is still under development and new features are added regularly but currently organizations should be able to set up and configure OpenID Connect/OAuth clients and scopes to fulfill most of their needs. If you think you cannot achieve some functionality please contact island.is support at <island@island.is>.

Organizations can manage who has access to the IAS admin portal on their behalf using the island.is delegation system (Umboðskerfi Ísland.is). Ideally a representative(s) of the institution or municipality manages all IAS settings on behalf of the institution/municipality. In the case where the technical knowledge to effectively use the admin portal is lacking, granting access to technical vendors is acceptable. We do however recommend that some representative of the institution/municipality monitors the usage of applications/permissions in the IAS admin portal.

To assist first time users in using the IAS admin portal we've created instructions for a few common use cases.

## Setting up a login for a webpage

Use case: The government institution MyOrg wants to setup a login for their service portal/my pages.

1. Go to the Application overview and click Create Application.
2. Enter a name, a matching ID will be auto-filled but can be edited if you wish.
3. Select environment. We recommend first creating the application in staging, finish all development and testing and then using the publish function to create an identical application in production. For the remainder of this guide we will assume that's the approach you took as well.
4. Application type should be Web Application.&#x20;
5. Click Create.
6. Under Application URLs fill in both the Callback URL and Logout URL fields. Both fields can hold multiple URLs with one URL per line, the list of URLs is most likely provided by your dev team. Don't forget to click Save settings once you're done.
7. Send the Client ID and Client Secret to your dev team. The ID and secret can be considered equivalent to a username and password combination, the ID can be made public but the secret MUST be kept private so we recommend using a secret sharing service such as <https://onetimesecret.com/> or <https://scrt.link/en> to safely send the secret via email or similar. Never send the secret in plaintext or share pictures of it. See [EXPOSED SECRET](#exposed-secret) for instructions on what to do if a secret is exposed.
8. Once development is complete and your login is ready to go live open the application again, click the drop-down in the top-right corner and select "Publish to Production"
9. In the pop-up window select "publish from Staging", this will copy all relevant settings from staging to production
10. Add application URLs for your production environment to the Callback URL and Logout URL fields.
11. Send the Client Secret for production to your dev or operation team, remember to keep the Client Secret private and follow the directions under [EXPOSED SECRET](#exposed-secret) in case the secret is exposed.

## Configuring Single Sign-On (SSO)

Use case: The government institution MyOrg wants to enable SSO for their service portal.

IAS has its own session, which provides the option of a **Single Sign-On (SSO)** experience. With SSO enabled, users who authenticate once can quickly log in to all other applications using the same IAS session without seeing the login screen again.

By default, **SSO is disabled for all new applications**, but administrators can enable it in the IAS admin portal.

#### Steps to configure SSO

1. Go to **Applications** and select your application.
2. Scroll down to the **Session lifecycle** section.
3. Check or uncheck **Allow single sign-on (SSO)**:
   * **Checked (SSO enabled)**: Users can authenticate once and re-use the IAS session across all other applications using this session.
   * **Unchecked (default)**: Users will always need to sign in separately to your application.
4. Click **Save settings**.

#### Forcing re-authentication

If you need to require a fresh login even when an IAS session exists:

* Use the `prompt=login` parameter when sending the authentication request.
* You should check the `auth_time` claim in the token to confirm that the login is recent.

#### Logging out with SSO enabled

* If a user logs out of your application, you **should perform an RP Initiated Logout**. This ensures the IAS session is terminated.
* Note: If a user logs out of another application, your application might still have a valid token until it expires. IAS does **not** guarantee single sign-out across all applications.

<figure><img src="/files/61ccHizRSDbasog3pkYJ" alt=""><figcaption></figcaption></figure>

## Enabling delegations (umboð) for an existing login

Use case: The government MyOrg wants to allow companies to submit documents to their service portal. This tutorial assumes you've already completed the steps in [Setting up a login for a webpage](#setting-up-a-login-for-a-webpage) and have a staging application for testing/development and a production application with live users.

1. Go to the Permissions overview and click Create Permission
2. Enter a name, a matching ID will be auto-filled but can be edited if you wish.
3. Enter a description, this should give users a clear and concise idea of what rights this permission will give.&#x20;
4. Select environment, as with creating an application we recommend creating the permission in staging first and completing all development work before going to production.
5. Add an english translation of both name and description for your permission.
6. Under Security & Capabilities, configure the access level for your scope.\
   Read/Write Access: When unchecked (default), the scope is displayed to users as "View" (Skoða). When checked, it is displayed as "View and edit" (Skoða og breyta). Choose the option that matches what kind of access your scope gives the user.
7. Under Delegations select which user groups should get this delegation.
   1. Procuration Holders: If selected Procuration Holders as registered in the Company Registry (Fyrirtækjaskrá) can log in on behalf of their companies.
   2. Legal Guardians: If selected Legal Guardians of children (up to 18 years old) as registered in the National Registry (Þjóðskrá) can log in on behalf of their children.
   3. [Legal Guardians Minor: If selected Legal Guardians of minors (up to 16 years old) as registered in the National Registry (Þjóðskrá) can log in on behalf of their children](#user-content-fn-1)[^1]. [ This is a custom calculated delegation type, based on the Legal Guardians registration in the National Registry but calculated from the date of birth of the child.](#user-content-fn-1)[^1]
   4. Custom Delegations: If selected users can grant permission to individuals to login on their behalf. If this option is selected it is critical that the name and description chosen in steps 2, 3 and 5 are clear to the user. When Custom Delegations is enabled,\
      additional configuration options become available:
      1. Service Categories (Þjónustuflokkur): Assign the scope to one or more service categories. Categories group scopes so\
         users can find them more easily when granting delegations. Select the appropriate category from the dropdown. If no suitable\
         category exists, contact <island@island.is>.
      2. Tags (Tögg): Optionally tag the scope to help users find and grant delegations for specific groups or tasks. Tags can be\
         added or removed using the dropdown. Not all scopes need tags — use them when they help users narrow down relevant\
         scopes. If you need a new tag, contact <island@island.is>.
   5. Legal Representative: If selected Legal Representatives as registered by the District Commissioner (Sýslumaður) can log in on behalf of their wards.
8. Go to Applications and select your application.&#x20;
9. Make sure you've selected "Staging" in the drop-down in the top right corner.
10. Under the Permissions section click Add Permission, find the permission you just created (you might have to refresh the page) and add the new permission. Don't forget to click Save Settings once you're done.
11. Under the Delegations section select the same options as you did for the permission. We also recommend checking "Always prompt delegations" as this will prompt your users to select a delegation (if there's multiple options) upon login. Before clicking "Save" make sure to un-check "Save in all environments", this ensures that the changes we make now are limited to Staging and won't affect the login process for live users.
12. Send the permission ID to your dev team and have them add it to the list of requested scopes during the login process.
13. Once development is complete and the use of the delegations ready to go live open the permission again, click the drop-down in the top-right corner and select "Publish to Production"
14. In the pop-up window select "Publish from Staging", this will copy all relevant settings from staging to production.
15. Go to Applications and select your application
16. Under the Permissions tab click Add Permission, find the permission you just created (you might have to refresh the page) and add the permission. Don't forget to click Save Settings once you're done.
17. Click the drop-down in the top-right corner and select "Staging"
18. Under the Delegations tab click the button that says "out of sync" and then click "sync settings from this environment". This will transfer all the settings we changed in step 6 from staging to production.

When deciding on a name and description for your permission, go to <https://island.is/minarsidur/adgangsstyring/umbod> and take a look at how other government agencies have worded their names and description. Creating a consistent experience and understanding for users who interact with multiple government agencies can improve the user experience and reduce risk of misunderstandings.

## Exposed Secret

In case of an exposed secret it is critical that the secret be replaced as soon as possible, before malicious parties are able to exploit the secret.&#x20;

1. Open your application in the IAS admin portal
2. Scroll to the bottom of the page, to the Danger Zone
3. Click Rotate Secret
4. Select if you wish to revoke the old secrets immediately, if you suspect that malicius parties already have access to the secret we recommend doing revoking of the secret immediately.
5. Click Generate, this will create a new secret for your client. Copy the new secret and send it to your ops team using some secure secret sharing method, see the section on [Setting up a login](#setting-up-a-login-for-a-webpage) for more information on secret sharing.
6. Confirm that the new secret works and logging in is possible.
7. If you checked "Rotate Secret" in step 4 you're done. If you didn't you'll see a warning box at the top of the page letting you know that multiple secrets are still active. Click Revoke old secrets to de-activate them.

[^1]:


# Notifications / Hnipp

### Introduction

Notifications are messages that inform users about relevant activities on island.is. They play a crucial role in enhancing user experience by keeping users updated without the need to be actively engaged with the app or website at all times.

#### Types of notifications

**In-App and In-Website Notifications (Always on)**

These notifications are visible when the user is using the app or website, the notification bell will show a visual cue when the user has an unseen notification, users can access all of their notifications for the last 6 months both in the app and website.

<figure><img src="/files/AQPkO2PhKSXBuPOs7kNp" alt=""><figcaption><p>island.is app showing a red dot on the notification bell</p></figcaption></figure>

**Push Notifications (Opt-in)**

Users can optionally get these messages as push notifications.  These messages are sent directly to a user's device, like a smartphone or tablet, and open the island.is app on the device when interacted with.<br>

<figure><img src="https://lh7-us.googleusercontent.com/pPs58K36ExjNtc4O6Ow55B5yXRPFs51_B67dYvzZ_MjQmSWRlbjYRXkBPPOaX4FlSipLMkmnGjuROnecOxKzK3ew-nOhU1TpuokujRRysf4FA1hG_SX43EfOacOoUWvz4c5MMedQbONFdevNXtbSEqI" alt=""><figcaption><p><em>example push notification</em></p></figcaption></figure>

**Email Notifications (Opt-in)**

Users can also optionally get these messages as email notifications. These messages are sent directly to the user's email inbox, and open the island.is website in a browser on the device when interacted with.

<figure><img src="https://lh7-us.googleusercontent.com/pCF4xZXy1Ya7lWKr1Q5UMPbb09P3xEJU2crhuK8-6ind1O7I5I7RltGk0gexyaKrXgHyOZNCp2ahAoor5toxakLiZgWfaIUNpGhTyCxJcVOFYybCNrOpqnafoKre12rXakoSYFhNywIARaBJvbZApzs" alt=""><figcaption><p>example email notification</p></figcaption></figure>

<br>


# New Notification Setup Guide

### Prerequisites

Your organisation needs to be already integrated into [Mailbox/Pósthólf](/products/postholf)

### Hnipp notification templates

A Hnipp notification template is a reusable resource for sending notifications to users, the template is cross-channel, so the message stays the same across web/app, push and email.

Title = 35 chars Body = 100 chars Internal body = 256 chars

A Hnipp notification consists of:

* **Title (35 chars)**: a short and simple descriptive text giving context
* **External Body (100 chars)**: a required description that **must not** contain any sensitive/private information, can be seen in external clients like email and outside app notifications and in internal clients if Internal Body is not provided
* **Internal Body (256 chars)**: an optional description that **might** contain sensitive/private information, can only be seen in internal clients behind login in website and app
* **Click Action Url**: An optional universal link that sends the user into a deeper context are in web or app related to the message

### Hnipp template variables

The templates are reusable, multi-lingual and can be injected with context specific variables, such as sender, recipient or context specific values

example template

```
Title: Nýtt skjal á Ísland.is
External Body: {{organization}} hefur sent þér nýtt skjal í pósthólfið þitt á Ísland.is
Internal Body: {{organization}} hefur sent þér nýtt skjal: {{documentName}}
Click Action Url: https://island.is/minarsidur/postholf/{{documentId}}
```

becomes:

```
Title: Nýtt skjal á Ísland.is
External Body: Fjársýslan hefur sent þér nýtt skjal í pósthólfið þitt á Ísland.is
Internal Body: Fjársýslan hefur sent þér nýtt skjal: 500.000 kr inneign tilbúin til útborgunar
Click Action Url: https://island.is/minarsidur/postholf/some-unique-document-id
```

Note in the example how the **Internal Body** contains user specific information while the **External Body** does not.

### How to setup a new Hnipp notification template

#### Create and publish

Get in touch with a Stafrænt Ísland contact to create and publish a new Hnipp notification template in the CMS.

#### Preview and test

Preview and test the notification by sending a test message to a test user via [Mailbox/Pósthólf](/products/postholf)-API using the new hnipp notification template in the development environment.\
In the example request below the Hnipp notification template is referred via the **templateId** property and if the template uses dynamic arguments those are provided in the **templateArguments** property

```
POST /api/v1/notifications
[
    {
        "kennitala": "0000000000",
        "senderKennitala": "0000000000",
        "templateId": "HNIPP.EXAMPLE.TEMPLATE",
        "templateArguments": {
            "salutation": "Hello world!" 
        },
        "publicationDate": "2023-04-19T14:50:04.4545645+00:00"
    }
]
```

### Verify Hnipp notification template message on all channels

Once a test message is sent verify the following for all supported languages:

* in-Website notification
  * message appears and looks correct under notification bell
  * clicking on the message performs the desired action
* in-App notification
  * message appears and looks correct under notification bell
  * clicking on the message performs the desired action
* Push notification
  * message is delivered and looks correct on the OS screen of a real test device\
    \&#xNAN;*NB. Test with a real device for actual results. Preferably both iOS and Android*
  * clicking on the message opens the island.is app and performs the desired action&#x20;
* Email notification
  * message looks correct in an email sent to a test user's email client
  * clicking on the message opens the island.is website and performs the desired action

### Well done!

Once a Hnipp notification template is set up and verified it is ready for mass-use on production.


# Notifications service workflow overview

### Workflow overview

The notification service receives a request to create a notification, the service processes the request and places it in a AWS SQS.&#x20;

#### Message processing

A worker periodically requests notifications from the **AWS SQS** queue in batches of up to 10 messages.

The worker handler fetches data needed to send out the notification, the template from Contentful and user specific information and tokens from the user profile service. Then proceeds to send the notification to the appropriate channel (e.g., push notification via Firebase Cloud Messaging, or email).

### Error Handling and Retries

* **Retry Logic**:\
  If a message fails during processing, the system automatically retries up to **three times**.
* **Dead Letter Queue (DLQ)**:\
  If a message fails after the maximum number of retries, it is moved to a **Dead Letter Queue**. Messages in the DLQ are not processed automatically and require **manual intervention** to reprocess.

### Debugging and monitoring

* **Message Tracking**:\
  Each message is assigned a unique `messageId`, which can be used to trace its lifecycle within the system.
* **Logging**:\
  Logs for message processing are available in **Datadog**.&#x20;


# Email notifications


# Pósthólfið

## Getting started

* Request access to the mailbox (í. Pósthólfið). You can apply for access to the mailbox at island.is' application site <https://island.is/postholf/stofnanir.\\>
  The application has to include information about the institution that is applying as well as information about the guarantor (í. ábyrgðaraðili) and technical point of contact.
* If the application is accepted, the technical point of contact will receive the following information:
  * ClientId / ClientSecret - To be able to use the Skjalatilkynning API
  * Audience
  * Scope
* The applicant needs to implement an executable that delivers document references to the mailbox by calling [Skjalatilkynning API](https://github.com/island-is/island.is/blob/main/handbook/technical-overview/postholf/postholf-03-interface-skjalatilkynning.md). An example can be seen in the Keyrsla section in the following link: <https://github.com/digitaliceland/postholf-demo>
* The applicant has to implement a callback service that returns a document when it's requested by the user. The service has to be implemented according to the [Skjalaveita API interface](/products/postholf/postholf-03-interface-skjalaveita). Example: <https://github.com/digitaliceland/postholf-demo>
* Information must be sent to Stafrænt Ísland regarding where (url) to call the aforementioned service.

## Content

* [Security Checklist](/products/postholf/postholf-00-security-checklist)
* [Introduction](/products/postholf/postholf-01-intro-and-overview)
* [Skjalatilkynning API](/products/postholf/postholf-02-interface-skjalatilkynning)
* [Skjalaveita API](/products/postholf/postholf-03-interface-skjalaveita)
* [Sequence Diagram](/products/postholf/postholf-04-sequence-diagram)
* [Interfaces](/products/postholf/postholf-05-interfaces)


# Security Checklist

This checklist defines requirements that Skjalaveita web services need to fulfill before a connection to the Ísland.is Pósthólf can take place. The purpose of this checklist is to prevent possible security issues when web services are implemented.

## Transport layer

All communication is encoded using HTTPS (TLS 1.2+). Web servers certificate is issued by a trusted certificate authority (not self signed).

* [ ] Communication is encoded on a server that supports TLS 1.2+.
* [ ] Certificates are issued by a trusted certificate authority.

## Authorization

The web service is implemented with OAuth 2.0, where an access token is verified against the authentication server's signed credentials. The web service also validates a scope and the token's expiration date. The web service is not accessible by any other means.

* [ ] The web service is only accessible with OAuth 2.0.
* [ ] The web service validates that the access token is signed by the authorization service.
* [ ] Authorization is only given when the correct scope is in the access token.
* [ ] An expired access token is rejected when used.

## Tokens

The Skjalaveita production environment only trusts tokens that are issued by the Ísland.is production authentication server. The Ísland.is test environment uses a different authentication server and is never be trusted in production.

* [ ] The production environment only trust the Ísland.is production authentication server.

## Access restriction

The web service's network layer is closed and only accessible by the IP addresses that the Ísland.is Pósthólf uses to query the service.

* [ ] The web service is only accessible by IP addresses that the Ísland.is Pósthólf uses.

## Form validation

An input hsa to be sanitized to avoid possible injections, the correct format is also ensured.

* [ ] The web service returns an error if the input is empty (i.e the nationalId or documentId is empty).
* [ ] The web service returns an error if the nationalId is incorrectly formatted.
* [ ] The web service returns an error if the documentId is not in the correct format. The format is determined by the Skjalaveita.
* [ ] The web service is protected against injections. <https://www.owasp.org/index.php/Top\\_10-2017\\_A1-Injection>

## Data input validation

When the Ísland.is Pósthólf retrieves a document from a Skjalaveita, it sends a nationalId and documentId pair. The Skjalaveita validates that the document is owned by the given nationalId. The document is not returned solely based on the documentId.

* [ ] The web service validates the nationalId and documentId pair with the document before it is returned.

## Logging

The web service logs all requests. The log contains the nationalId, documentId and when the document was requested.

* [ ] Requests are logged.


# Introduction

## Introduction

The mailbox (í. Pósthólfið) is a closed area on Ísland.is. It contains and stores documents from the public sector (Document providers) to individuals and companies. Individuals and companies with an Icelandic ID number have their own mailbox.

Communication between the mailbox and the document provider is through a REST API. Document providers register a reference to new documents for publication on Island.is (also referred as index or documentIndex). The documents themselves are stored by the document provider they originate from.\
Users can identify themselves on Island.is and see a list of documents which belong to them. If the user retrieves a document the mailbox retrieves the document from the document provider. In other words, the document is only retrieved on user request.

Document providers need to implement the [Skjalaveita API](/products/postholf/postholf-03-interface-skjalaveita) which the mailbox has access to. The service needs to be created according to the pre-defined interface. The mailbox will be able to make a homogeneous query on any document provider where the endpoint different for each document provider.

## Overview

![](/files/Fb0tnuFUU91EbcVXWTG6)

Access Tokens are issued by the same idP for Skjalatilkynning API and Skjalabirting API (i.e., same idP for both directions).


# Skjalatilkynning API

API that document providers use to register and maintain document references, along with sending notifications.

Document Providers authenticate themselves with OAuth 2.0 Authentication using Client Credentials Grant (<https://tools.ietf.org/html/rfc6749#section-4.4>)

All operations that modify document references can take an array of 1-200 changes at time. They return an array result for each change in the same order as they were entered.

## Categories

Returns possible categories of documents in Icelandic. Example of categories: Líf og Heilsa (e. Life and Health), Atvinna (e. Employment), Fjármál (e. Finances)

> GET /api/v1/documentindexes/categories

#### Response

```json
["string"]
```

| Variable | Type   | Description                                                                 |
| -------- | ------ | --------------------------------------------------------------------------- |
| \[]      | String | Document categories that can be used when document reference is registered. |

## Types

Returns possible types of documents in Icelandic. Example types: Launaseðill (e. Paycheck), Greiðsluseðill (e. Invoice), Yfirlit (e. Overview/Summary)

> GET /api/v1/documentindexes/types

#### Response

```json
["string"]
```

| Variable | Type   | Description                                                         |
| -------- | ------ | ------------------------------------------------------------------- |
| \[]      | String | Document type that can be used when registering document reference. |

## DocumentIndex

A document provider registers references to documents. Each document is uniquely identified by a combination of `documentID` and `owner_kennitala`, which together form a unique key pair that can only be registered once. However, a document can be registered multiple times for different `owner_kennitala`, for example, when a couple needs access to the same document. Once the `publication_date` has passed, the recipient is notified and the document becomes visible. A published document **can not be removed** or have its contents modified, except if it was registered to an incorrect recipient.

> POST /api/v1/documentindexes

#### Request Body

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "senderKennitala": "string",
    "senderName": "string",
    "authorKennitala": "string",
    "caseId": "string",
    "category": "string",
    "type": "string",
    "subType": "string",
    "subject": "string",
    "documentDate": "datetime",
    "publicationDate": "datetime",
    "minimumAuthenticationType": "string",
    "fileType": "string",
    "urgentUntil": "datetime"
  }
]
```

Array of document references. It‘s possible to submit 1-200 references at a time

| Variable                  | Optional | Type       | Description                                                                                                                                                                                                                                                                  |
| ------------------------- | -------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| kennitala                 | N        | String(10) | Kennitala of the document owner/recipient, that is the one who should see the document. Has to be a valid kennitala.                                                                                                                                                         |
| documentId                | N        | String(50) | A unique identifier within a document provider. Used to retrieve a document, when user requests it.                                                                                                                                                                          |
| senderKennitala           | N        | String(10) | Sender kennitala (usually some institution). (A document provider can represent and register documents for many senders)                                                                                                                                                     |
| senderName                | N        | String     | Name of the sender.                                                                                                                                                                                                                                                          |
| authorKennitala           | Y        | String(10) | Author kennitala (Usually same as the Sender (KennitalaSendanda))                                                                                                                                                                                                            |
| caseId                    | Y        | String     | Case number within the institution (sender).                                                                                                                                                                                                                                 |
| category                  | N        | String(25) | Document category. Only allowed predefined document categories. The operation SaekjaFlokka (e. GetCategories) returns the types that are available.                                                                                                                          |
| type                      | Y        | String(25) | Document type. Only allowed predefined document types. The operation SaekjaTegundir (e. GetTypes) returns the types that are available.                                                                                                                                      |
| subType                   | Y        | String     | Sub-type, selected by a document provider.                                                                                                                                                                                                                                   |
| subject                   | N        | String(80) | Document name or description, free text up to 80 characters.                                                                                                                                                                                                                 |
| documentDate              | N        | Datetime   | Date of document (not publication date).                                                                                                                                                                                                                                     |
| publicationDate           | Y        | Datetime   | Indicates when the document should appear to the user. For example, if the publisher wants to submit a reference tor a document to be published at the next month. If nothing is set, the document is displayed immediately. Date Display may not exceed 60 days in advance. |
| minimumAuthenticationType | Y        | String     | <p>Minimum authentication type/strength to open/view the document. The default is LOW.<br>LOW = User/pass<br>SUBSTANTIAL = Two factor authentication (User/Pass and additionally an SMS)<br>HIGH = Client Certificate</p>                                                    |
| fileType                  | Y        | String     | <p>Indicates the file type, current supported types are "url", "pdf" and "html". Unsupported file types are still available for download but will not be displayed properly.<br>If fileType is not provided "pdf" is assumed.</p>                                            |
| urgentUntil               | Y        | Datetime   | Marks the document as urgent. Requires special permission to be utilized.                                                                                                                                                                                                    |

#### Response

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "wantsPaper": true,
    "success": true,
    "errors": ["string"]
  }
]
```

| Property   | Type    | Description                                                           |
| ---------- | ------- | --------------------------------------------------------------------- |
| kennitala  | String  | Kennitala of the document owner/recipient.                            |
| documentId | String  | A unique identifier for the reference within the document provider    |
| wantsPaper | Boolean | [Paper preference](#paper-preference) of the document owner/recipient |
| success    | Boolean | Successful                                                            |
| errors\[]  | String  | Error messages (only if success=false).                               |

## Notification

Creates a 'hnipp' notification that sends both a push notification and an email to the recipient. Notifications utilize templates to manage the their content. Read more about templates here: [Notifications / Hnipp ](/products/notifications-hnipp/new-notification-setup-guide)

> POST /api/v1/notifications

#### Request Body

```json
[
  {
    "kennitala": "string",
    "senderKennitala": "string",
    "templateId": "string",
    "templateArguments": {
      "argKey": "argValue"
    },
    "publicationDate": "datetime"
  }
]
```

Array of notifications. It‘s possible to submit 1-200 references at a time

| Variable          | Optional | Type       | Description                                                                                                                                              |
| ----------------- | -------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| kennitala         | N        | String(10) | Kennitala of the recipient. Has to be a valid kennitala.                                                                                                 |
| senderKennitala   | N        | String(50) | Sender kennitala (usually some institution). (A document provider can represent and send notifications for many senders)                                 |
| templateId        | N        | String     | An ID referencing a template, the template contains the textual information for the notification in all supported languages.                             |
| templateArguments | -        | Object     | Arguments that fill in the dynamic portions of a template. Should contain key-value pairs the template requires. Required if the template has arguments. |
| publicationDate   | Y        | DateTime   | Indicates when the notification should be pushed to the user. If nothing is set, the notification is queued immediately.                                 |

#### Response

```json
[
  {
    "kennitala": "string",
    "success": true,
    "errors": ["string"]
  }
]
```

| Property  | Type    | Description                                      |
| --------- | ------- | ------------------------------------------------ |
| kennitala | String  | Kennitala of the recipient.                      |
| success   | Boolean | Indicates if the requets was a success           |
| errors\[] | String  | Any error messages (only if the request failed). |

### Example request

Registering two notifications to different individuals.

```json
[
  {
    "kennitala": "0000000000",
    "senderKennitala": "0000000000",
    "templateId": "HNIPP.EXAMPLE.TEMPLATE",
    "templateArguments": {
      "salutation": "Hello world!"
    },
    "publicationDate": "01-01-2024"
  },
  {
    "kennitala": "0000000001",
    "senderKennitala": "0000000000",
    "templateId": "HNIPP.EXAMPLE.TEMPLATE",
    "templateArguments": {
      "salutation": "Greetings world!"
    },
    "publicationDate": "01-01-2024"
  }
]
```

## Withdraw

An operation to withdraw a document that is no longer available for publication. This can **only** be used if the document was sent to an **incorrect recipient** or if the `publication_date` has not passed. If a document needs to be withdrawn after it was opened by the recipient, the document provider must notify the recipient of the withdrawal.

> POST /api/v1/documentindexes/withdraw

#### Request Body

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "reason": "string"
  }
]
```

Array of withdrawn references. It‘s possible to withdraw 1-200 references at a time

| Variable   | Type       | Description                                                                                                           |
| ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------- |
| kennitala  | String(10) | Owner/recipient kennitala.                                                                                            |
| documentId | String     | A unique identifier which was used when the document was registered (for the reference within the document provider). |
| reason     | String     | Reason for withdrawal.                                                                                                |

#### Response

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "success": true,
    "errors": ["string"]
  }
]
```

| Property   | Type    | Description                                                        |
| ---------- | ------- | ------------------------------------------------------------------ |
| kennitala  | String  | Kennitala of the document owner/recipient.                         |
| documentId | String  | A unique identifier for the reference within the document provider |
| success    | Boolean | Successful                                                         |
| errors\[]  | String  | Error messages (only if success=false).                            |

## Read

> POST /api/v1/documentindexes/read

If a document provider has published a document in a location other than island.is, the document can be marked as read. Thus, the user can see that he has opened the document regardless of where he opened it.

#### Request Body

```json
[
  {
    "kennitala": "string",
    "documentId": "string"
  }
]
```

It‘s possible to mark 1-200 references as read at a time

| Variable   | Type       | Description                                                                                                           |
| ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------- |
| kennitala  | String(10) | Owner/recipient kennitala.                                                                                            |
| documentId | String     | A unique identifier which was used when the document was registered (for the reference within the document provider). |

#### Response

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "success": true,
    "errors": ["string"]
  }
]
```

| Property   | Type    | Description                                                        |
| ---------- | ------- | ------------------------------------------------------------------ |
| kennitala  | String  | Kennitala of the document owner/recipient.                         |
| documentId | String  | A unique identifier for the reference within the document provider |
| success    | Boolean | Successful                                                         |
| errors\[]  | String  | Error messages (only if success=false).                            |

## Update Reference

> POST /api/v1/documentindexes/updateReference

If the document's publication date has not elapsed, the document provider can change the documents reference.

#### Request Body

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "updatedDocumentId": "string"
  }
]
```

It‘s possible to change 1-200 references at a time

| Variable          | Type       | Description                                                                                                           |
| ----------------- | ---------- | --------------------------------------------------------------------------------------------------------------------- |
| kennitala         | String(10) | Owner/recipient kennitala.                                                                                            |
| documentId        | String     | A unique identifier which was used when the document was registered (for the reference within the document provider). |
| updatedDocumentId | String     | The new unique identifier.                                                                                            |

#### Response

```json
[
  {
    "kennitala": "string",
    "documentId": "string",
    "success": true,
    "errors": ["string"]
  }
]
```

| Property   | Type    | Description                                                        |
| ---------- | ------- | ------------------------------------------------------------------ |
| kennitala  | String  | Kennitala of the document owner/recipient.                         |
| documentId | String  | A unique identifier for the reference within the document provider |
| success    | Boolean | Successful                                                         |
| errors\[]  | String  | Error messages (only if success=false).                            |

## Paper Preference

A document recipient can register to receive a physical paper document on Island.is. It is up to the document provider to keep track of and send paper mail if the recipient wants it.

> GET /api/v1/{kennitala}/paper

Returns the paper preference of the kennitala.

#### Response

```json
{
    "kennitala": "string",
    "wantsPaper": true,
}
```

| Variable   | Type    | Description              |
| ---------- | ------- | ------------------------ |
| kennitala  | String  | Kennitala of the user    |
| wantsPaper | Boolean | Does the user want paper |
|            |         |                          |

> GET /api/v1/paper

Returns recipients that wish to receive a physical paper document.

#### Query parameters

| Variable | Type   | Description                      |
| -------- | ------ | -------------------------------- |
| page     | Number | Requested page                   |
| pageSize | Number | Item count of the requested page |

#### Response

```json
[
  {
    "kennitala": "string",
    "wantsPaper": true,
  }
]
```

| Property   | Type    | Description              |
| ---------- | ------- | ------------------------ |
| kennitala  | String  | Kennitala of the user    |
| wantsPaper | Boolean | Does the user want paper |


# Skjalaveita API

## Skjalaveita API

Service that document providers need to implement. All document providers need to implement the same interface. The mailbox will call this service to retrieve documents from the document provider when a user wants to view the document.

HTTPS communication is required. The backend system will identify itself with JWT in the Authorization header using the Bearer schema. The service MUST validate the signature, issuer, expiry dates, audience and scope

### Document

The operation returns an owner's document. The service should only return a document if the `documentId` and `owner_kennitala` matches a registered document in the document provider's system.

> GET $BASE\_URL$/{kennitala}/documents/{documentId}?authenticationType={authenticationType}\&includeDocument={includeDocument}

Request Parameters:

| Variable           | Type    | Description                                                                                                                                                                                          |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| kennitala          | String  | Owners/recipients kennitala.                                                                                                                                                                         |
| documentId         | String  | A unique identifier for the reference within the document provider.                                                                                                                                  |
| authenticationType | String  | <p>Strength of authentication of the user/recipient of the document.<br>LOW = User/pass<br>SUBSTANTIAL = Two factor authentication (User/Pass and additionally SMS)<br>HIGH = Client Certificate</p> |
| includeDocument    | Boolean | If the actual document should be returned or only the metadata                                                                                                                                       |

Response:

```json
{
  "type": "string",
  "content": "string",
  "actions": [
    {
      "type": "string",
      "title": "string",
      "data": "string",
      "icon": "string" 
    }
  ]
}
```

| Property name | Type                  | Description                                                                                                                                                 |
| ------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type          | String                | Document form (file ending). For example, pdf. If nothing is given, pdf is the default and recommended if there is not a special reason for something else. |
| content       | Base64Binary (String) | The document/file content base64 encoded.                                                                                                                   |
| actions       | List(Action)          | See [Skjalaveita API](/products/postholf/postholf-03-interface-skjalaveita#actions)                                                                         |
| **Or**        |                       |                                                                                                                                                             |
| type          | String                | If set to “url”, island.is will redirect the user to a document delivery site. User is transferred between along with a signed SAML2 xml.                   |
| content       | String                | Url                                                                                                                                                         |
| actions       | List(Action)          | See [Skjalaveita API](/products/postholf/postholf-03-interface-skjalaveita#actions)                                                                         |
| **Or**        |                       |                                                                                                                                                             |
| type          |                       | If set to “html”, page with the html content will be displayed in new tab.                                                                                  |
| content       | String                | Html to display the user. The HTML must contain all "inline" to display. HTML must not contain javascript.                                                  |
| actions       | List(Action)          | See [Skjalaveita API](/products/postholf/postholf-03-interface-skjalaveita#actions)                                                                         |

## Actions

Actions are **optional**, they provide additional actions for the end user. Actions appear as buttons above the document once it has been opened.

| Property name | Type   | Description                                                                                                                                             |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type          | string | The type of action                                                                                                                                      |
| title         | string | The text the button displays                                                                                                                            |
| data          | string | See [#supported-actions](#supported-actions "mention")                                                                                                  |
| icon          | string | The icon on the action button [list of supported icons](https://github.com/island-is/island.is/blob/main/libs/island-ui/core/src/lib/IconRC/iconMap.ts) |

### Supported actions

<table><thead><tr><th width="374">type</th><th>data</th><th>Description</th><th data-hidden></th></tr></thead><tbody><tr><td>file</td><td>-</td><td>Opens the document in a new tab</td><td></td></tr><tr><td>url</td><td>string</td><td>A url</td><td></td></tr></tbody></table>

### Example

<figure><img src="/files/9Q66ps7mCC2iSc5D9EWk" alt=""><figcaption></figcaption></figure>

```json
[
    {
        Type = "url",
        Title = "Mínar síður",
        Data = "https://island.is/minarsidur/",
        Icon = "open"
    },
    {
        Type = "file",
        Title = "Sækja sem PDF"
    }
]
```

## Sequence Diagram

Sequence diagram that describes how Island.is retrieves a document and displays the user. This is valid when documents that are in the form of a non-external connection are required, such as pdf.

![](/files/SyRWAXnrUVTbEE1lqIcV)


# Sequence Diagram

Sequence diagram that describes how island.is retrieves a document and displays the user. This is valid when documents that are in the form of a non-external connection are required, such as pdf.

![](/files/SyRWAXnrUVTbEE1lqIcV)


# Interfaces

## Skjalatilkynning OpenApi

[Skjalatilkynning Test](http://test-skjalatilkynning-island-is.azurewebsites.net/swagger/ui/index)

[Skjalatilkynning Production](https://skjalatilkynning-island-is.azurewebsites.net/swagger/ui/index)

## Skjalaveita OpenApi

```json
{
  "openapi": "3.0.1",
  "info": {
    "title": "Skjalaveita API",
    "version": "v1"
  },
  "paths": {
    "/api/v1/customer/{kennitala}/documents/{documentId}": {
      "get": {
        "tags": ["Documents"],
        "parameters": [
          {
            "name": "kennitala",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "authenticationType",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Document": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "content": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "errorMessage": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    }
  }
}
```

Also available here:

<https://test-skjalaveita-island-is.azurewebsites.net/swagger/v1/swagger.json>


# Organization Documents API

Used by organizations to query and fetch documents that are registered to their national ID. The API is only available through [Straumurinn (X-Road)](/products/x-road)

## Authentication

The [Island.is Authentication Service](/products/auth) with client credentials flow is used for authentication.

Organizations can integrate with this service by:

1. Creating a Machine to Machine Client (Application) in the IDS Admin.
2. Requesting API access for the client via Island.is support.

## API

#### Document List

Returns a list of documents registered to the organization. A maximum of 100 items can be retrieved in each request.

## GET /api/v1/Documents

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents":{"get":{"tags":["Documents"],"parameters":[{"name":"senderKennitala","in":"query","schema":{"type":"string"}},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"categoryId","in":"query","schema":{"type":"string"}},{"name":"typeId","in":"query","schema":{"type":"string"}},{"name":"archived","in":"query","schema":{"type":"boolean","default":false}},{"name":"order","in":"query","schema":{"$ref":"#/components/schemas/Order"}},{"name":"opened","in":"query","schema":{"type":"boolean"}},{"name":"page","in":"query","schema":{"type":"integer","format":"int32","default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","format":"int32","default":15}},{"name":"bookmarked","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentListView"}}}},"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"Order":{"enum":["Ascending","Descending"],"type":"string"},"DocumentListView":{"type":"object","properties":{"documents":{"type":"array","items":{"$ref":"#/components/schemas/DocumentListItem"}},"unreadCount":{"type":"integer","format":"int32"},"totalCount":{"type":"integer","format":"int32"}},"additionalProperties":false},"DocumentListItem":{"required":["categoryId","senderName","senderNationalId","subject"],"type":"object","properties":{"id":{"type":"string","format":"uuid"},"documentDate":{"type":"string","format":"date-time"},"publicationDate":{"type":"string","format":"date-time","nullable":true},"senderNationalId":{"type":"string"},"senderName":{"type":"string"},"subject":{"type":"string"},"categoryId":{"type":"string"},"opened":{"type":"boolean"},"bookmarked":{"type":"boolean"},"urgent":{"type":"boolean"},"replyable":{"type":"boolean"}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Get Document

Retrieves the document and its contents. Three content types are supported, only one content type is used per document. \
\
`content` is a base64 string of the documents content\
`htmlContent` is plaintext HTML\
`urlContent` is a URL linking to the document

## GET /api/v1/Documents/{documentId}

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/{documentId}":{"get":{"tags":["Documents"],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentDTO"}}}},"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DocumentDTO":{"required":["fileType"],"type":"object","properties":{"fileType":{"type":"string"},"content":{"type":"string","nullable":true},"htmlContent":{"type":"string","nullable":true},"urlContent":{"type":"string","nullable":true}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Read Document

Marks document as read

## POST /api/v1/Documents/{documentId}/read

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/{documentId}/read":{"post":{"tags":["Documents"],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Archive Document

Sets the documents archived status

## POST /api/v1/Documents/{documentId}/archive

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/{documentId}/archive":{"post":{"tags":["Documents"],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentArchiveRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/DocumentArchiveRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/DocumentArchiveRequest"}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DocumentArchiveRequest":{"type":"object","properties":{"archived":{"type":"boolean"}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Bookmark Document

Sets the documents bookmarked status

## POST /api/v1/Documents/{documentId}/bookmark

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/{documentId}/bookmark":{"post":{"tags":["Documents"],"parameters":[{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentBookmarkRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/DocumentBookmarkRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/DocumentBookmarkRequest"}}}},"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DocumentBookmarkRequest":{"type":"object","properties":{"bookmarked":{"type":"boolean"}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Document Types

Returns all document types associated with the organization’s documents

## GET /api/v1/Documents/types

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/types":{"get":{"tags":["Documents"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MessageTypeDTO"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"MessageTypeDTO":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

#### Document Categories

Returns all document categories associated with the organization’s documents

## GET /api/v1/Documents/categories

>

```json
{"openapi":"3.0.4","info":{"title":"IslandIs Documents API V1","version":"v1"},"tags":[{"name":"Documents"}],"paths":{"/api/v1/Documents/categories":{"get":{"tags":["Documents"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MessageCategoryDTO"}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"MessageCategoryDTO":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false},"ErrorResponse":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"integer","format":"int32"},"detail":{"type":"string"},"instance":{"type":"string"}},"additionalProperties":false}}}}
```

{% embed url="<https://openapi.gitbook.com/o/-MJWAvhHdFCiWEQqlyr6/spec/DocumentsAPI.json>" %}


# Straumurinn (X-Road)

Straumurinn is a secure data exchange layer, based on X-Road.

**Links:**

[Overview of Straumurinn on island.is](https://island.is/en/o/digital-iceland/island-services/straumurinn)

[X-Road® Data Exchange Layer Official Website](< https://x-road.global/>)

[Nordic Institute for Interoperability Solutions (NIIS) Office Website](https://www.niis.org/)


# Architecture Guidelines for Service Providers and Consumers

## Overview <a href="#id-19bfb586-a73f-4335-8e13-11e141dd907f" id="id-19bfb586-a73f-4335-8e13-11e141dd907f"></a>

*Straumurinn* is based on X-Road, an open source data exchange layer solution that enables organizations to exchange information over the Internet. X-Road is a centrally managed distributed data exchange layer between information systems that provides a standardized and secure way to produce and consume services.

While configuration, service registration and certification is centrally managed, individual service providers and consumers manage or use their own Security Servers, which are resilient to disruptions in the operation of the central services. Availability is one of the main concerns for the operators of individual Security Services, and options in that regard are thus a focus of this document.

![](/files/gCejYPCBu2BxjWExNzDu)

Figure 1: [X-Road security architecture](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-sec_x_road_security_architecture.md)

The exchange of information over the X-Road security layer is synchronous. There is no queuing mechanism offered by X-Road, as its main purpose is to serve as a secure transport layer, and thus the handling of errors is the responsibility of the corresponding client and provider information systems.

### Further reading <a href="#d33a23fc-c9ce-497f-9957-61de4700f10a" id="d33a23fc-c9ce-497f-9957-61de4700f10a"></a>

* [X-Road Architecture](https://x-road.global/architecture)
* [X-Road Security Architecture](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-sec_x_road_security_architecture.md)
* [X-Road Architecture - Technical Specification](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-g_x-road_arhitecture.md)

## Availability <a href="#id-2c8b484c-479c-4a28-9dc0-211bc028a9c9" id="id-2c8b484c-479c-4a28-9dc0-211bc028a9c9"></a>

A benefit of the distributed design of X-Road is that no single component is a system-wide bottleneck or point of failure. The availability of security services for each service consumer and provider can be increased with redundant configurations. There are two possible approaches to increase the availability of X-Road security servers: Internal and external load balancing. Those two approaches entail a trade-off between simplicity and flexibility.

The Security Server has an internal client-side load balancer, and it also supports external load balancing. The client-side load balancer is a built-in feature, and it provides high availability. Instead, external load balancing provides both high availability and scalability from a performance point of view.

### Internal load balancing <a href="#id-8e8e3a9e-b444-4f1a-adb6-d64c1424b28b" id="id-8e8e3a9e-b444-4f1a-adb6-d64c1424b28b"></a>

Internal load balancing is a feature built into the X-Road security servers. The solution provides high availability, but not scalability, as identical services can be registered on multiple Security Servers and are chosen on a "Fastest Wins" basis. If the same service is available on multiple Security Servers, the requests are load-balanced amongst the Security Servers but the load is not evenly distributed between all the provider side Security Servers. If one of the Security Servers goes offline, requests are automatically routed to other available Security Servers. The service client's security server will choose the first available service provider's security server when forwarding the request. Thus, redundancy is inherent to the X-Road message transport protocol, provided that there are multiple security servers configured to offer the same service.

The configuration of internal load balancing is simpler than external load balancing, as the Security Servers take care of routing the requests and verification of certificates internally. It does require the effort of configuring the services independently, though identically, on each Security Server; adding a new service requires adding it manually to each Security Server intended to handle requests to that service. The addition of each Security Server requires an independent registration process with the X-Road central to be completed.

![](/files/NG3ECtfkSbKnNtpXVa2B)

Figure 2: “The Fastest Wins” - the server that responds the fastest to TCP connection establishment request is used by a client Security Server. See [Balancing the Load in X-Road](https://www.niis.org/blog/2018/6/25/balancing-the-load).

### External load balancing <a href="#id-1dfbab03-054f-4967-a7c5-9910c90118ed" id="id-1dfbab03-054f-4967-a7c5-9910c90118ed"></a>

Both high availability and scalability, from a performance point of view, can be achieved with the X-Road Security Server support for the use of external internet-facing load balancers. In this setup an external LB is used in front of a Security Server cluster and the LB is responsible for routing incoming messages to different nodes of the cluster based on the configured load balancing algorithm. Using the health check API of the Security Server, the LB detects if one of the nodes becomes unresponsive and quits routing messages to it.

Setting up a Security Server cluster is more complicated compared to the internal load balancing that is a built-in feature and enabled by default. Security Server version upgrades are more complex with an external load balancer, as the upgrade process must be coordinated within the cluster. On the other hand, adding new nodes to a cluster is easy, as the normal registration process is not required, because all the nodes in the cluster share the same identity. In contrast, when relying on the internal load balancing, each node is independent and has its own identity – adding a new Security Server means that full registration process must be completed.

![](/files/iCQNb17fuSv6JKJsUGjC)

Figure 3: An external LB can be used in front of a Security Server cluster and the LB is responsible for routing incoming messages to different nodes. See [Balancing the Load in X-Road](https://www.niis.org/blog/2018/6/25/balancing-the-load).

### Further reading <a href="#id-89cf0edb-da88-4faf-b0aa-3d490642dcf3" id="id-89cf0edb-da88-4faf-b0aa-3d490642dcf3"></a>

* [X-Road Architecture](https://x-road.global/architecture)
* [Balancing the Load in X-Road](https://www.niis.org/blog/2018/6/25/balancing-the-load)
* [X-Road Security Architecture: Availability](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-sec_x_road_security_architecture.md#5-availability)
* [X-Road: Security Server Architecture: Redundant Deployment](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-ss_x-road_security_server_architecture.md#52-redundant-deployment)
* [X-Road: External Load Balancer Installation Guide](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/LoadBalancing/ig-xlb_x-road_external_load_balancer_installation_guide.md)

The following table summarizes the Availability and Performance configuration options discussed above:

## Availability and performance configuration options.

| Architecture                                                                                              | Pros                                                                                                                                | Cons                                                              |
| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| [Single Server](https://www.notion.so/Single-Server-966858d704f84db28fc10938c52ecbf4)                     | Simple Set up                                                                                                                       | Low resiliency, Best Effort                                       |
| [Internal Load Balancing](https://www.notion.so/Internal-Load-Balancing-3717244103c2428ba10cb6c2d9dd7746) | High Availability, Feature built into X-Road                                                                                        | Requires independent configuration and registration for each node |
| [External Load Balancing](https://www.notion.so/External-Load-Balancing-90e87293ccba4f61938402bdb47a03ea) | Offers both High Availability and High Performance (with e.g. auto-scaling). One-time configuration and registration for all nodes. | Initial configuration more complex.                               |

## Monitoring <a href="#a2a0b91e-4ee9-49d3-a38b-66ca387aaf86" id="a2a0b91e-4ee9-49d3-a38b-66ca387aaf86"></a>

X-Road offers environmental and operational monitoring. The operational monitoring processes operational statistics (such as which services have been called, how many times, what was the size of the response, etc.) of the security servers. Operational data of the X-Road Security Servers is collected and made available for external monitoring systems (e.g. Zabbix, Nagios) via corresponding interfaces.

The load balancing support includes a health check service that can be used to ping the security server using HTTP to see if it is healthy and likely to be able to send and receive messages.

### Further reading <a href="#id-3c283098-20da-47fe-b8b8-f001c663cecc" id="id-3c283098-20da-47fe-b8b8-f001c663cecc"></a>

* [X-Road: Operational Monitoring Daemon Architecture](https://github.com/nordic-institute/X-Road/blob/develop/doc/OperationalMonitoring/Architecture/arc-opmond_x-road_operational_monitoring_daemon_architecture_Y-1096-1.md)
* [X-Road: External Load Balancer Installation Guide - Health check service configuration](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/LoadBalancing/ig-xlb_x-road_external_load_balancer_installation_guide.md#34-health-check-service-configuration)

## Data Exchange <a href="#d0595987-2ecb-4275-89aa-d07d62de59d2" id="d0595987-2ecb-4275-89aa-d07d62de59d2"></a>

X-Road can be integrated with information systems using multiple patterns. From X-Road’s point of view it’s enough that an information system implements the X-Road Message Protocol for SOAP or REST. When it comes to REST, you can publish existing REST services without any changes, as-is. Instead, SOAP services must support X-Road specific SOAP headers.

The X-Road metaservices can be used to retrieve lists of Service Providers, Central Services and lists of services offered by an X-Road client.

### Further reading <a href="#id-4daaf8f9-8206-4efa-bb23-a84c6405e6b1" id="id-4daaf8f9-8206-4efa-bb23-a84c6405e6b1"></a>

* [X-Road Message Protocol for REST](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-rest_x-road_message_protocol_for_rest.md)
* [X-Road Message Protocol for SOAP](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-mess_x-road_message_protocol.md)
* [X-Road: Service Metadata Protocol for REST](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-mrest_x-road_service_metadata_protocol_for_rest.md)

## Installation and Upgrading <a href="#id-950b9f07-4e8e-4ab9-a8f3-eefc1b860e06" id="id-950b9f07-4e8e-4ab9-a8f3-eefc1b860e06"></a>

The currently recommended installation approach, for production ready X-Road deployments, is to use Operating System specific software installation packages, which are available for the Ubuntu and RedHat Enterprise Linux Operating Systems. Specifically, Icelandic variants of those packages should be used when setting up Security Servers to be registered in the Icelandic X-Road instance *Straumurinn* – see links below.

As a general rule, X-Road Security Servers should be no further than two releases behind the latest X-Road release.

In the currently recommended (non-containerized) production ready configuration, upgrading is mostly a matter of upgrading the Operation System specific X-Road packages. Manual steps may be required, such as performing a database migration. Release notes and the X-Road Knowledge Base should be studied carefully before each upgrade, especially when major releases are involved.

### Further reading <a href="#id-4b148a7d-2554-45fc-a1dc-823bae02adbb" id="id-4b148a7d-2554-45fc-a1dc-823bae02adbb"></a>

* [How to Set Up a Security Server?](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/4916118/How+to+Set+Up+a+Security+Server)
  * see specifically the example upgrade commands in that parent document
* [X-Road Knowledge Base](https://confluence.niis.org/display/XRDKB/X-Road+Knowledge+Base)

### Further Reading <a href="#d9df2a4e-368b-42d5-a7fb-d1e460848eca" id="d9df2a4e-368b-42d5-a7fb-d1e460848eca"></a>

* X-Road Logs Explained – [Part 1](https://www.niis.org/blog/2018/5/27/x-road-logs-basics), [Part 2](https://www.niis.org/blog/2018/6/3/x-road-logs-explained-part-2) and [Part 3](https://www.niis.org/blog/2018/6/12/x-road-logs-explained-part-3)
* [Signed Document Download and Verification Manual](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-sigdoc_x-road_signed_document_download_and_verification_manual.md)


# Setting up an X-Road Security Server

Security Server Installation, Registration and Configuration

## Hardware requirements

* 64-bit dual-core Intel, AMD or compatible CPU; AES instruction set support is highly recommended
* 2 CPU
* 4 GB RAM
* 10 GB free disk space (OS partition) and 20-40 GB free disk space on the “/var” partition
* 100 Mbps network interface card

## Operating System Requirements

This guide assumes one of the following:

* **Red Hat Enterprise Linux**
  * RHEL8+
* **Ubuntu**
  * 20.04 LTS
  * 22.04 LTS

***Note**: Installing and configuring an X-Road Security Server requires  `sudo`* permissions on the host.

{% hint style="info" %}

#### Running in a container

Running the X-Road Security Server in a container is outside the scope of this guide, but you can refer to the official [Security Server Sidecar User Guide](< https://github.com/nordic-institute/X-Road/blob/develop/doc/Sidecar/security_server_sidecar_user_guide.md>) for guidance.&#x20;
{% endhint %}

## Network Configuration

Check the [Network Configuration sub-page](#network-configuration).

## FQDN Requirements

The FQDN of a Security Server should easily identity the Tier and Owner:

<table><thead><tr><th width="241">Environment</th><th>Tier</th><th>FQDN Template</th></tr></thead><tbody><tr><td><code>IS-DEV</code></td><td>Development</td><td><code>xroad-dev.&#x3C;member's domain>.is</code></td></tr><tr><td><code>IS-TEST</code></td><td>Testing / QA / UAT / Staging et.al.</td><td><code>xroad-test.&#x3C;member's domain>.is</code></td></tr><tr><td><code>IS</code></td><td>Production</td><td><code>xroad-prod1.&#x3C;member's domain>.is</code><br><code>xroad-prod2.&#x3C;member's domain>.is</code></td></tr></tbody></table>

## Installing X-Road

### Provision the `xroad` POSIX user

The X-Road Server should be run under a dedicated POSIX user, usually named `xroad`

Create this user by running the following command:

```sh
sudo useradd \
--system \
--home /var/lib/xroad \
--no-create-home \
--shell /bin/bash \
--user-group \
--comment "X-Road system user" \
xroad
```

{% hint style="info" %}
If that user will be used for interactive SSH log-ins, then we must ensure that the Security Server PIN (see below) doesn't get cleared (even though auto-login is configured), by running the following command:

```bash
loginctl enable-linger xroad
```

{% endhint %}

### Follow the installation guide

NIIS maintains a guide for setting up Security Servers on Ubuntu and RHEL inside their knowlegebase, which you can find here: [How to Set Up a Security Server?](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/4916118/How+to+Set+Up+a+Security+Server)&#x20;

While following the guide above, take care to override the official documentation with specific steps for the Icelandic environment (*Straumurinn*), outlined at [https://github.com/digitaliceland/Straumurinn](https://github.com/digitaliceland/Straumurinn#getting-started-installing-security-server-and-intial-configuration)

#### Certificate generation&#x20;

During installation, a dialog will appear asking for **host** and **IP information** for certificate generation. The latter set of the dialog will be for configuring certificates for the `xroad-proxy-ui-api`.&#x20;

Here it may be desirable to change the value from the auto-detected machine host name to a domain name used for accessing the Admin UI:

![](/files/-MSDDXe8F28AfuXu9ATl)

![](/files/-MSDDXeENQrasy1aMhff)

## Registration

Once a Security Server has been successfully installed, the Admin UI can be accessed by pointing a  web browser at [https://SECURITYSERVER:4000/](https://securityserver:4000/) .&#x20;

### Required configuration for registration

Before being able to import a Configuration Anchor, the Security Server IP and FQDN must be whitelisted by the operator of the *Straumurinn* X-Road Central Services.&#x20;

To register a Security Server into *Straumurinn,* the following configuration values are required:

#### 1. Outgoing IP Address of the Security Server&#x20;

{% hint style="info" %}

####

The public outgoing IP address of the server can be found with with the following command from a Security Server terminal session:

```
$ curl ifconfig.me
```

{% endhint %}

#### **2. FQDN of the Security Server**

{% hint style="info" %}
Refer to the section about [#fqdn-requirements](#fqdn-requirements "mention").
{% endhint %}

#### **3. Member's Kennitala /  SSN**

### Registration contact

To register, an email containing the values listed above the should be sent to the operator of the *Straumurinn* X-Road Central Server at <hjalp@ok.is>

#### Example email for registering a Security Server to Central.

<figure><img src="/files/hnfwGaeGgnMgQzJKyPd3" alt=""><figcaption><p>Example email for registering a X-Road Security Server to Central</p></figcaption></figure>

## Post-registration steps

Have a look at the [Security Server initial configuration](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ig-ss_x-road_v6_security_server_installation_guide.md#3-security-server-initial-configuration) guide from X-Road. Some of the next steps are derived from there.

### Disable message payload logging

The `xroad-securityserver-is` variant has the message logging disabled by default, from X-Road version 6.24.0 onwards.

### Software Token PIN

{% hint style="danger" %}
Keep the the PIN secret. Keep it safe.
{% endhint %}

During the Security Server initial configuration, we need to generate a password called the "software token PIN".

The PIN is a 12 digit, alpha-numeric password:&#x20;

* <https://en.wikipedia.org/wiki/Personal_identification_number>
* <https://en.wikipedia.org/wiki/ISO_9564#PIN_length>

You will be asked to supply the PIN during [Initial Configuraion (see below)](#initial-configuration).

#### Configure Auto-Login PIN entry functionality

{% hint style="warning" %}
If Auto-Login is not configured, the server will require **manual** entry of the Soft Token PIN during startup / restart, which can have implications for the Security Server's reliability.
{% endhint %}

For the PIN to be entered automatically when starting X-Road services, refer to the [X-Road: Autologin User Guide](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/Utils/ug-autologin_x-road_v6_autologin_user_guide.md)

#### Test auto-login PIN entry functionality

To verify that auto-login PIN entry works as expected, you can try stopping and starting all the X-Road services like this:

```bash
for i in xroad-confclient xroad-proxy xroad-signer xroad-monitor xroad-opmonitor xroad-proxy-ui-api ;\
do \
   echo "stopping $i"; \
   sudo service $i stop; \
done;
sudo systemctl list-units "xroad*"
for i in xroad-confclient xroad-proxy xroad-signer xroad-monitor xroad-opmonitor xroad-proxy-ui-api; \
do \
   echo "starting $i"; \
   sudo service $i start; \
done
```

### Ensure if all services are up and running

```bash
sudo systemctl list-units "xroad*"
```

### Enable health check endpoint

Refer to the [Health check service configuration](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/LoadBalancing/ig-xlb_x-road_external_load_balancer_installation_guide.md#34-health-check-service-configuration) for information on enabling the health check endpoints.

## Initial Configuration

### Configuration Anchors

Start by acquiring the Configuration Anchor for the X-Road network, found here: <https://github.com/digitaliceland/Straumurinn/tree/master/Anchor>

Next, point your browser at the Security Server, on port 4000 and log in.

![The X-Road Security Server Login Screen](/files/-MSDDXeOOGSUpSiP_2Cd)

Upload the environment's[ configuration anchor.](#start-by-acquiring-the-configuration-anchors)

![Step 1 of the Initial Configuration Wizard, which allows the User to upload a Configuration Anchor](/files/-MSDDXeRFMIeg6G-dA8O)

After anchor has been uploaded, it needs to be confirmed.

Ensure that the "Hash Generated" corresponds to the information on the Central Server.

Click \[CONFIRM].

![Configuration Anchor Confirmation Dialog](/files/-MSDDXeUkagUJWEHFrJc)

The Configuration Anchor has now been configured and should show you something like the following:

![A successfully configured Configuration Anchor](/files/-MSDDXeXR2VesdYiVagY)

### Owner Member

In the initial configuration screen input the values as follows.

* Member Class - the Member Class of the organization that maintains the central server.
* Member Code - the Member Code of the organization that maintains the central server.
* Member Name - is auto completed when Member Code is added.
* Security Server Code - unique code identifying the Security Server.
  * Use short-name for Server Code
  * Do not use FQDN, ".", "/" or "".
    * Some extensions use dots as separators, e.g. REST Adapter Service.
  * X-Road Message Protocol imposes some restrictions on the characters that can be used in X-Road identifiers. The following characters SHALL NOT be used in the identifier values:
    * Colon
    * Semicolon
    * Slash
    * Backslash
    * Percent
    * Path identifiers (such as /../)
    * Non-printable characters (tab, newline etc.)
  * <https://github.com/nordic-institute/X-Road/blob/6d60774c0b4e5368e70943c17a2ae6dfaa513259/doc/Protocols/pr-mess_x-road_message_protocol.md#27-identifier-character-restrictions>
  * <https://github.com/nordic-institute/X-Road/blob/6d60774c0b4e5368e70943c17a2ae6dfaa513259/doc/Protocols/pr-rest_x-road_message_protocol_for_rest.md#48-identifier-character-restrictions>

![Step 2 of the Initial Configuration Wizard, which allows the User to configure the Owner Member of the Security Server](/files/-MSDDXeeEgNzpnevdgLq)

### Software Token PIN

* PIN - the password that protects the security server's secret keys.
* Repeat PIN - repeat the above PIN.

{% hint style="danger" %}
Keep the PIN secret. Keep it safe.
{% endhint %}

![Step 3 of the Initial Configuration Wizard, which allows the USer to set the Software Token PIN.](/files/-MSDDXehfN6WFTkfQvJ_)

The initial configuration was saved successfully.

### CSR certificates

![Configuration window for adding members, clients or subsystems](/files/-MSDDXel3Bf_A4qQyRJP)

The security server asks for PIN code.

Click the *Please enter soft token PIN* link.

![An X-Road Security Server Admin UI page showing a red banner with the message "Please enter soft token PIN" along with a button for logging in with the PIN](/files/-MSDDXepHA7UDEf0Fzps)

Clicking the link navigates to Keys and Certificates page.

* Click \[LOG IN] on the `softToken` Service.
* Enter PIN Code&#x20;
* Click \[LOG IN] in the modal window.

![Logging in with PIN Code](/files/-MSDDXeriLztL7AvXuSy)

The red error message bar should now disappear.

## Final steps

### Configure Timestamping Services

Go to: Settings > Timestamping Services and click \[ADD]

![The  Settings -> System Parameters page which shows the empty Timestamping Services.](/files/-MSDDXevMUVoovmV6IGj)

Pick a time-stamping service from the list and click \[OK.]

![A modal for adding a Timestamping Service.](/files/-MSDDXezSXc70_mlJz0Z)

The message "Timestamping message added" should appear.

![Admin UI: The Settings -> System Parameters page which shows that aTimestamping service has been added](/files/-MSDDXf--WXaSoRHcow0)

### Configure SIGN and AUTH Keys

#### SIGN Key

Navigate to "KEYS AND CERTIFICATES"

![The Keys and Certificate Page](/files/-MSDDXf0182qQHFhvekz)

Click \[ADD KEY]

![The wizard for generating a certificate signing key ](/files/-MSDDXf1agX_pwotwYap)

Enter ”*sign*” for the "Key Label" and click \[NEXT]

![The CSR Details page inside the Add Key wizard.](/files/-MSDDXf2abTAuzNVkX3w)

Fill out the form with the following values:

* **Usage**: *SIGNING*
* **Client**: *Select the relevant Client from the dropdown.*
* **CSR Format:** *PEM*

Click \[GENERATE CSR]

![The Generate CSR page inside the Add Key wizard](/files/-MSDDXf5ZgT0iCPOB_zH)

Click \[DONE]

![Final confirmation page of the Add Key wizard](/files/-MSDDXf9qUMoeZ44sG4T)

The CSR should be downloaded to browser's download folder.

![An overview of SIGN and AUTH keys, showing that a CSR for the SIGN key has been created.](/files/-MSDDXfCQ1GiXbvygNLw)

***

#### The AUTH key

If you are not already there, start by navigating to "KEYS AND CERTIFICATES"->"SIGN AND AUTH KEYS" of the Admin UI (see above).

Click \[ADD KEY]

\
Enter “auth” and click \[NEXT]

![Part 1 of the The Add Key wizard, showing "Key Label" being set to "auth"](/files/-MSDDXfGYPpL6qT5E4NX)

Choose AUTHENTICATON and change CSR Format to PEM

Fill out the form with the following values:

* **Usage**: *AUTHENTICATION*
* **Certification Service:** *Select the appropriate certification service (there should only be 1)*
* **CSR Format:** *PEM*

![Part 2 of the The Add Key wizard: CSR details](/files/-MSDDXfJOPAa2OILi4A_)

Enter your Server DNS name (CN)

![Part 3 of the Add Key Wizard: Generate CSR](/files/-MSDDXfMZVAOiADYWm9g)

Press GENERATE CSR

![Final confirmation page of the Add Key wizard](/files/-MSDDXfQDxeQj5O3VEuS)

The certificate request is downloaded to browser's download folder.

![An overview of SIGN and AUTH keys, showing that a CSR for both the SIGN and AUTH keys have been created.](/files/-MSDDXfRNFPDvGUFCZXO)

Now you can see that there are two keys in the overview, Sign and Auth.

The certificate request should be sent to <hjalp@ok.is>.

### Import Certificates

Navigate to KEYS AND CERTIFICATIONS and click \[IMPORT CERT].

#### Import the AUTH Certificate

Navigate to and select the .pem file containing your certificate.

![The "KEYS AND CERTIFICATIONS" and screen overlaid by a MacOS File System Browser highlighting a .pem file.](/files/-MSDDXfStilZTjKgTSxI)

![The "SIGN AND AUTH KEYS" showing a successfully imported AUTH Certificate](/files/-MSDDXfTKXpiX8qWjhUF)

#### Activate auth signed certificate

Click the name of the certificate (test.xrd.island.is...) and press Activate

*SCREENSHOT NEEDED*

#### Import the SIGN Certificate

![](/files/-MSDDXfUaixYeWjhVzTC)

![](/files/-MSDDXfV2Twz4PPTy6O0)

![](/files/-MSDDXfWAteNiDT1zXgF)

Finally press **Register** on the auth certificate and enter inn the FQDN of the server and press ADD

![A "Registration request" modal which accepts the Security Server DNS name](/files/-MSDDXf_n9627tJokpR1)

!["SIGN AND AUTH KEYS" Screen showing that the status of AUTH Certificate is  "Registration in progress"](/files/-MSDDXfbU_vaK6uilJHF)

!["SIGN AND AUTH KEYS" Screen showing that both SIGN and AUTH Certificates have been Registered.](/files/-MSDDXfdaNd4BX-dGRUy)

## Confirm communication between two security servers

```bash
curl --insecure -H "X-Road-Client: IS-TEST/COM/5302922079/Origo-client" "
https://origo-staging.xroad.coldcloudlab.com/r1/IS-TEST/GOV/7005942039/VMST-Protected/APIS/company?name=origo
"
```

IS-**DEV**

**Ísland.is to Skatturinn**:

```bash
curl -H "X-Road-Client: IS-DEV/GOV/10000/island-is-client" "http://localhost:8080/r1/IS-DEV/GOV/10006/Skatturinn-Protected/APIS-v1/company?name=skatturinn"
```

IS-**TEST**

**Ísland.is to Skatturinn:**

```bash
curl -H "X-Road-Client: IS-TEST/GOV/5501692829/island-is-client" "http://localhost:8080/r1/IS-TEST/GOV/5402696029/Skatturinn-Protected/APIS-v1/company?name=skatturinn"
```

## Removal of Security Server

#### Ubuntu

```bash
#!/bin/bash

set -x
sudo apt-get purge xroad-base
sudo apt-get autoremove
sudo rm -rf /etc/xroad
sudo rm -rf /usr/share/xroad
sudo rm -rf /var/lib/xroad
sudo rm -rf /var/log/xroad
sudo rm -rf /var/tmp/xroad
sudo apt-get purge nginx
sudo -u postgres dropdb messagelog
sudo -u postgres dropdb serverconf
sudo -u postgres dropdb op-monitor
sudo -u postgres psql -c "drop user serverconf"
sudo -u postgres psql -c "drop user messagelog"
sudo -u postgres psql -c "drop user opmonitor"
sudo -u postgres psql -c "drop user serverconf_admin"
sudo -u postgres psql -c "drop user messagelog_admin"
sudo -u postgres psql -c "drop user opmonitor_admin"
sudo apt-get --purge remove postgresql\*
sudo rm -rf /etc/postgresql/
sudo rm -rf /var/lib/postgresql
sudo userdel -r postgres
```

#### RHEL

```bash
#!/bin/bash

set -x

sudo yum remove xroad-base
sudo rm -rf /etc/xroad
sudo rm -rf /usr/share/xroad
sudo rm -rf /var/lib/xroad
sudo rm -rf /var/log/xroad
sudo rm -rf /var/tmp/xroad
sudo yum remove nginx
sudo -u postgres dropdb messagelog
sudo -u postgres dropdb serverconf
sudo -u postgres psql -c "drop user serverconf"
sudo yum remove postgresql
```


# Network Configuration

## Network configuration

The X-Road Security Servers mediate service calls and service responses between Information Systems.&#x20;

They can be placed in a DMZ between the Information Systems they serve and the Internet.&#x20;

### X-Road Network Architecture Diagram

<figure><img src="/files/XAgU0ArsUfBlI65vtVXT" alt=""><figcaption><p>X-Road Network Architecture</p></figcaption></figure>

### Port configuration

A Security Server requires the following open ports for proper functioning:

| Port                                    | Purpose                                                                                                                                                                                                      |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Inbound ports from external network** | Ports for inbound connections from the external network to the security server                                                                                                                               |
| TCP 5500                                | Message exchange between security servers                                                                                                                                                                    |
| TCP 5577                                | Querying of OCSP responses between security servers                                                                                                                                                          |
| **Outbound ports to external network**  | Ports for outbound connections from the security server to the external network                                                                                                                              |
| TCP 5500                                | Message exchange between security servers                                                                                                                                                                    |
| TCP 5577                                | Querying of OCSP responses between security servers                                                                                                                                                          |
| TCP 4001                                | Communication with the central server                                                                                                                                                                        |
| TCP 80                                  | Downloading global configuration from the central server                                                                                                                                                     |
| TCP 80,443                              | Most common OCSP and time-stamping services                                                                                                                                                                  |
| **Inbound ports from internal network** | Ports for inbound connections from the internal network to the security server                                                                                                                               |
| TCP 4000                                | User interface and management REST API (local network). **Must not be accessible from the internet!**                                                                                                        |
| TCP 80, 443                             | Information system access points (local network). **Must not be accessible from the external network without strong authentication. If open to the external network, IP filtering is strongly recommended.** |
| **Outbound ports to internal network**  | Ports for inbound connections from the internal network to the security server                                                                                                                               |
| TCP 80, 443, *other*                    | Producer information system endpoints                                                                                                                                                                        |

### Central Server IP Addresses

The following table contains the CIDR masks / IP addresses of the central components of the Icelandic X-Road network which need to be whitelisted by all Security Servers.

<table><thead><tr><th width="136">Component</th><th width="189" align="right">IS</th><th width="224" align="right">IS-TEST</th><th align="right">IS-DEV</th></tr></thead><tbody><tr><td>Central Server</td><td align="right"><code>176.57.224.0/25</code></td><td align="right"><code>176.57.224.128/25</code></td><td align="right"><code>176.57.227.96/27</code></td></tr><tr><td>Mgmt. Security Server</td><td align="right"><code>176.57.224.0/25</code></td><td align="right"><code>176.57.224.128/25</code></td><td align="right"><code>176.57.227.96/27</code></td></tr><tr><td>Central Monitoring Server</td><td align="right"><code>34.252.193.131</code></td><td align="right"><code>34.253.108.248</code></td><td align="right"><code>3.250.245.108</code></td></tr></tbody></table>


# X-Road - Uppfærsla á öryggisþjónum

## Leiðbeiningar vegna uppfærslu X-Road hugbúnaðar á öryggisþjónum <a href="#uppfaerslaax-roadoeryggisthjonum-leidbeiningarvegnauppfaerslux-roadhugbunadaraoeryggisthjonum" id="uppfaerslaax-roadoeryggisthjonum-leidbeiningarvegnauppfaerslux-roadhugbunadaraoeryggisthjonum"></a>

#### Undirbúningur <a href="#uppfaerslaax-roadoeryggisthjonum-undirbuningur" id="uppfaerslaax-roadoeryggisthjonum-undirbuningur"></a>

* Taka afrit af vélinni (snapshot) eða ganga úr skugga um að afrit sé tiltækt
* Taka saman lykilorð og PIN fyrir signer console token login
* Fara yfir hvaða þjónustur og pakkar verða uppfærðir sem snúa að xroad og taka niður útgáfunúmerið
* Fara vel yfir laust pláss á diskum og bæta við áður en uppfærsla er keyrð af stað
* Uppfæra þarf X-Road í stökkum, ef núverandi útgáfa er t.d. 6.x þá þarf að uppfæra svona:
  * 6.25.x -> 6.26.3 -> 7.0.4 -> 7.1.3
  * Hægt að uppfæra með þessum hætti án þess að endurræsa á milli
  * Hægt að fara í X-Road útgáfu 7.1.3 án þess að uppfæra stýrikerfið (eins og Ubuntu 18 í 20 eða RHEL7 í RHEL8/9)

Þekkt vandamál:

* Ef Ubuntu öryggisþjónn hefur verið uppfærður og ekki xroad, þá þarf að skoða `/etc/apt/sources.list` og:
  1. Tryggja að xroad repo-ið vísar í Ubuntu útgáfuna sem öryggisþjóninn er á
  2. Virkja repo-ið ef það hefur verið comment-að út.
  3. Til þess að uppfæra úr Ubuntu 20.04 í 22.04 þarf fyrst að uppfæra x-road í 7.2.x

### Uppfæra RHEL/CentOS <a href="#uppfaerslaax-roadoeryggisthjonum-uppfaerarhel-centos" id="uppfaerslaax-roadoeryggisthjonum-uppfaerarhel-centos"></a>

Eftirfarandi leiðbeiningar miðast við að uppfæra frá einni útgáfu í aðra, ef taka þarf mörg stökk, eins og frá 6.x í 7.1.3 þarf að endurtaka neðangreint

```sh
# Pakkasvæði
# NIIS repo fyrir RHEL7
# sudo yum-config-manager --add-repo https://artifactory.niis.org/xroad-release-rpm/rhel/7/current
# NIIS repo fyrir RHEL8
# sudo yum-config-manager --add-repo https://artifactory.niis.org/xroad-release-rpm/rhel/8/current

# Nota íslenskan mirror
# sudo RHEL_MAJOR_VERSION=$(source /etc/os-release;echo ${VERSION_ID%.*})
# sudo yum-config-manager --add-repo https://mirrors.opensource.is/xroad/xroad-release-rpm/rhel/${RHEL_MAJOR_VERSION}/current/

# Skoða diskapláss
df -h

# Hvaða þjónustur eru keyrandi?
sudo systemctl list-units|grep -i xroad
 
# Hvaða pakkar eru uppsettir og í hvaða útgáfum
rpm -qa|grep -i xroad
 
# Bæta exclusion fyrir xroad yum repo (eða NIIS repo ef það er notað)
sudo vim /etc/yum.repos.d/mirrors.opensource.is_xroad_xroad-release-rpm_rhel_7_current_.repo
 
# Til þess að halda okkur innan útgáfu 7.0.4 er hægt að undanskilja öllum 7.1 útgáfum af xroad pökkunum
# Bætt er við þessarri línu í xroad yum repo skránna sem staðsett er undir /etc/yum.repos.d
# Passa að taka út þau exclude til þess að komast áfram í næstu útgáfu
# Dæmi:
exclude=xroad-*-7.2* xroad-*-7.3* xroad-*-7.4* xroad-*-7.5* xroad-*-7.6* xroad-*-7.7*xroad-*-7.8* xroad-*-7.9* xroad-*-8.*

# Einnig er hægt að setja repoið í disabled svo x-road uppfærist ekki sjálfkrafa við yum update

#
# Nota Yum Versionlock
#
# Það er líka hægt að læsa X-road útgáfunni með Yum Versionlock
# Sjá nánari leiðbeiningar hér -> https://access.redhat.com/solutions/98873
# Ef notað er versionlock þá þarf að fjarlægja exclude línuna hér að ofan.
# Dæmi um notkun á version lock sem læsir útgáfu á öllum xroad pökkum í 7.1.3

# sudo yum versionlock add xroad-*7.1.3*
# sudo yum versionlock list

###

# Kanna hvað verður uppfært
sudo yum clean all
sudo yum check-update xroad-*
 
# Taka niður xroad þjónustur og ganga úr skugga um að þær séu ekki keyrandi
sudo systemctl stop xroad-*
sudo systemctl list-units|grep -i xroad
 
# uppfæra stýrikerfið og xroad
sudo yum update
 
# endurræsa eftir uppfærslu
 
# Fara einnig yfir að núverandi útgáfur séu réttar
rpm -qa|grep -i xroad
 
# Og að þjónusturnar séu keyrandi
sudo systemctl list-units|grep -i xroad
 
# skrá aftur inn signer token PIN - leiðbeiningar miðað við að notandinn sé xroad
# Einnig hægt að skrá inn PIN frá X-Road UI
sudo su - xroad
signer-console li 0
signer-console lt
```

### Uppfæra Debian / Ubuntu <a href="#uppfaerslaax-roadoeryggisthjonum-uppfaeradebian-ubuntu" id="uppfaerslaax-roadoeryggisthjonum-uppfaeradebian-ubuntu"></a>

Ef kerfið keyrir á Ubuntu 18.04 er hægt að uppfæra frá 6.26.3->7.0.4→7.1.3 og svo uppfæra Ubuntu 18.04 í Ubuntu 20.04 og svo áfram í 22.04.

Þessu er þá stýrt með pin-xroad skránni hér að neðan.

Leiðbeiningar fyrir in-place upgrade úr Ubuntu 18.04 í 20.04 eru hér → <https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/4915336/Security+Server+Ubuntu+18.04+to+20.04+In-place+Upgrade.>

Leiðbeiningar fyrir in-place upgrade úr Ubuntu 18.04 í 20.04 eru hér → <https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/82313217/Security+Server+Ubuntu+20.04+to+22.04+In-place+Upgrade.>

Eftirfarandi leiðbeiningar miðast við að uppfæra frá einni útgáfu í aðra, ef taka þarf mörg stökk, eins og frá 6.x í 7.1.3 þarf að endurtaka neðangreint

```sh
# Skoða diskapláss
df -h

# Sækja GPG lykil
curl https://artifactory.niis.org/api/gpg/key/public | sudo apt-key add -

# Ef það þarf að bæta við REPO
# Nota NIIS
# sudo apt-add-repository -y "deb https://mirrors.opensource.is/xroad/xroad-release-deb $(lsb_release -sc)-current main"

# Eða nota íslenskan NIIS mirror
# sudo apt-add-repository -y "deb https://mirrors.opensource.is/xroad/xroad-release-deb $(lsb_release -sc)-current main"

sudo apt update
 
# Einnig hægt að nota mirror frá mirrors.opensource.is
# sudo apt-add-repository -y "deb https://mirrors.opensource.is/xroad/xroad-release-deb $(lsb_release -sc)-current main"
 
# Hvaða þjónustur eru keyrandi?
sudo systemctl list-units|grep -i xroad
 
# Til þess að festa útgáfu allra xroad pakka í 7.0.4, þarf búa til skrá undir /etc/apt/preferences.d

# Fyrir Ubuntu 18.04
 
cat <<EOF | sudo tee /etc/apt/preferences.d/pin-xroad
Package: xroad-*
Pin: version 7.0.4-1.ubuntu18.04
Pin-Priority: 1337
EOF
 
# Fyrir Ubuntu 20.04
 
cat <<EOF | sudo tee /etc/apt/preferences.d/pin-xroad
Package: xroad-*
Pin: version 7.0.4-1.ubuntu20.04
Pin-Priority: 1337
EOF

# Fyrir Ubuntu 22.04
 
cat <<EOF | sudo tee /etc/apt/preferences.d/pin-xroad
Package: xroad-*
Pin: version 7.2.2-1.ubuntu22.04
Pin-Priority: 1337
EOF
 
sudo apt update
sudo apt list --upgradable |grep -i xroad
 
# Taka niður xroad þjónustur
sudo systemctl stop xroad-*
sudo systemctl list-units|grep -i xroad
 
# Uppfæra stýrikerfið og xroad pakka
sudo apt upgrade -V
 
# endurræsa eftir uppfærslu
 
# Fara yfir Og að þjónusturnar séu keyrandi
sudo systemctl list-units|grep -i xroad
 
# skrá aftur inn signer token PIN - leiðbeiningar miðað við að notandinn sé xroad
# Einnig hægt að skrá inn PIN frá X-Road UI
sudo su - xroad
signer-console li 0 # Setja inn PIN
signer-console lt
```

## Ýmsir tenglar sem snúa að uppfærslum

{% embed url="<https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/4916447/How-to+articles>" %}

{% embed url="<https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/369393684/Security+Server+Cluster+RHEL+8+or+RHEL+7+to+RHEL+9+Upgrade>" %}

{% embed url="<https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/369393684/Security+Server+Cluster+RHEL+8+or+RHEL+7+to+RHEL+9+Upgrade>" %}

{% embed url="<https://www.x-tee.ee/docs/live/xroad/ss_ubuntu20_inplace_upgrade.pdf>" %}

{% embed url="<https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/82313217/Security+Server+Ubuntu+20.04+to+22.04+In-place+Upgrade>." %}


# Straumurinn - Notkun og umsýsla

Straumurinn – Notkun og umsýsla

## Hvað er Straumurinn og hvernig gagnast hann

Straumurinn byggir á X-Road, opinni útfærslu gagnaflutningslags sem gerir stofnunum og fyrirtækjum kleift að skiptast á upplýsingum yfir Internetið. X-Road er dreift kerfi, sem lýtur miðlægri stjórn, þar sem veiting og öflun þjónustu er gerð möguleg með stöðluðum og öruggum hætti.

Meðan miðlæg stjórn er höfð með samskipan, skráning þjónusta og sannvottun, þá reka þjónustuveitendur og -neytendur sína eigin öryggisþjóna sem þola truflanir í rekstri miðlægu þjónustanna. X-Road tryggir leynd, heilleika og samvirkni milli aðilia sem eiga í gagnasamskiptum.

![](/files/-MSCYSP6MgOBYjcwvoBh)

## Vistkerfi Straumsins

Umhverfi Straumsins samanstendur af stofnunum og fyrirtækjum sem hafa sameinast um að nýta sömu X-Road uppsetninguna til að veita og þiggja þjónustu. Umsjónaraðilar Straumsins stýra því hverjum er heimilt að tengjasta þessu samfélagi, ásamt því að setja reglur og viðmið.

![](/files/-MSCYSPECPQtPn9qi3wh)

## Traust net

Þó X-Road sé opinn hugbúnaðar, þá er nauðsynlegt að fara í gegnum skráningarferli til að tengjast umhverfi Straumsins. Í þessu ferli er auðkenni hvers aðila og tæknilegir tengipunktar vottuð með skilríkjum sem eru gefin út af miðlægri vottunarstöð (CA). Haldið er utan um auðkennin miðlægt en samskipti eiga sér stað beint milli neytenda þjónustu og veitenda.

Beining samskipta byggir á auðkennum aðila og þjónusta, sem er varpað af X-Road yfir á raunverulega staðsetningu þjónustanna á neti. Öll skráning varðandi samskipti er geymd hjá hverjum aðila um sig og þriðju aðilar hafa ekki aðgang að þeim gögnum. Óhrekjanleiki samskipta yfir Strauminn er tryggður með tímastimplum og stafrænum undirskriftum. Samskiptaskrár X-Road er hægt að nota sem sönnunargagn fyrir rétti.

![](/files/-MSCYTuDBAE3fxl7S6Kn)

![](/files/-MSCYSPPY87F_uJx-Cp-)

## Aðgangsheimildir

Með X-Road er hægt að stjórna aðgangi að þjónustum. Stjórn aðgangsheimilda byggir á auðkennum aðila og einstakra þjónusta.

Lykilatriði í Straumnum er að þjónustuveitandi eigi sín gögn og hafi stjórn á aðgangi að þeim. Þó þjónusta hafi verið gefin út á Straumnum er ekki þar með sagt að hún sé sjálfkrafa aðgengileg öllum meðlimum hans. Vanalega er aðgangur veittur á grundvelli upplýsingakerfis: Þjónustuveitandi heimilar tilteknu upplýsingakerfi aðgang að tiltekinni þjónustu.

![](/files/-MSCYSPcbrk1aK7NRqZc)

Hlutverk innan umhverfis Straumsins

* frá <https://www.niis.org/blog/2020/3/30/x-road-implementation-models>

## Vöktun og skýrslugjöf

X-Road veitir möguleika á vöktun og skýrslugjöf sem er hægt að nýta til að safna gögnum um aðgerðir í umhverfi Straumsins. Upplýsingarnar er hægt að nota til að mæla notkun einstakra þjónusta, öðlast skilning á tengslum milli ólíkra upplýsingakerfa og þjónusta, fylgjast með heilsufari þjónusta, útgáfum X-Road hugbúnaðarins, o.s.frv. Hver aðili Straumsins getur fylgst með sínum gögnum, meðan umsjónaraðilar hafa aðgang að umhverfisgögnum allra aðila.

## Gagnaskipti þvert á landamæri

Í X-Road er innbyggður stuðningur við gagnaskipti yfir landamæri með samtengingu umhverfa. Meðlimir umhverfa sem hafa verið tengd saman geta gefið út og þegið þjónustur sín á milli eins og þeir tilheyri sama vistkerfinu. Þannig er til dæmis hægt að koma á gagnaskiptum milli landa.

## Vefþjónustur í Straumnum

Upplýsingaveitur tengjast Straumnum í formi vefþjónusta, REST eða SOAP, sem eru skráðar í öryggisþjón viðkomandi stofnunar / aðila. Innan öryggisþjóna eru skráð undirkerfi (e. subsystem) og vefþjónustur skráðar innan þeirra. Aðgangsheimildir að endapunktum vefþjónusta eru veittar X-Road undirkerfum annarra aðila.

Skráning vefþjónustu í Strauminn felst í því að finna henni stað í undirkerfi (subsystem) á vegum viðkomandi aðila / stofnunar. Vefþjónustan er skráð í undirkerfið og aðgangsheimildir veittar öðrum undirkerfum (annarra aðila).

## X-Road undirkerfi (subsystem / client)

Í umsjónarvefviðmóti X-Road öryggisþjóns er hægt að skrá undirkerfi og senda skráningu þeirra í miðlæga umsýsluhluta Straumsins. Þannig er miðlægt haldið utan um undirkerfi þeirra stofnana sem eru tengdar Straumnum. Uppfletting og leit í skráningu undirkerfa er möguleg frá öryggisþjóni hvers aðila.

Skráning undirkerfis felst í því að velja að bæta við undirkerfi í umsjónarvefviðmótinu: Undir *Clients* flipanum er smellt á *Add Subsystem*:

![](/files/-MSCYSPje7T5uxyVsaVf)

Á skjánum sem þá birtist er undirkerfinu gefið nafn samkvæmt nafnavenju undirkerfa Straumsins, sem hefur áhrif á birtingu vefþjónusta undirkerfisins í Viskuausunni – sjá 2.2 *Nafnavenjur Straumsins og skráning vefþjónusta í vörulista sem birtist á* [*island.is*](https://island.is/s/stafraent-island/vefthjonustur).

![](/files/-MSCYSPso30-tcmu8PI_)

Þá er séð til þess að hakað sé við *Register subsystem* og smellt á hnappinn *Add Subsystem*. Gluggi birtist til staðfestingar skráningu undirkerfisins í miðlæga hluta Straumsins:

![](/files/-MSCYSQ1B3wfjFa2CtMp)

### Nafnavenjur Straumsins og skráning vefþjónusta í Vörulista vefþjónusta

Tæknilega er mögulegt að notast við eitt undirkerfi (subsystem) fyrir allar aðgerðir á vegum stofnunar – það gæti þjónað sem bæði biðlari (client) og veitandi (provider) upplýsinga – en til aðgreiningar og stuðnings við söfnun vefþjónusta í vörulista sem birtur er að [island.is](https://island.is/s/stafraent-island/vefthjonustur), þá styðst Straumurinn við nafnavenju í formi viðskeyta í nöfnum undirkerfa, sem gefa til kynna tilgang þeirra:

* \<stofnun / kerfisflokkur>**-Protected** Almennar vefþjónustur sem er æskilegt að skráist inn í vörulista vefþjónusta, svo aðilar Straumsins geti flett upp á tilvist þeirra, ættu að vera skráðar í undirkerfi með heiti sem endar á „-Protected“.
* \<stofnun / kerfisflokkur>**-Client** Þegar upplýsingakerfi stofnunar framkvæma fyrirspurnir yfir Strauminn í vefþjónustur annarra stofnana, þá þurfa þau að tilgreina eigið undirkerfi sem sendir fyrirspurnina fyrir þeirra hönd. Nafn þessa undirkerfis ætti að hafa viðskeytið „-Client“. Þegar aðilar Straumsins veita aðgangsheimildir að sínum vefþjónustum, þá er gefin heimild fyrir undirkerfi viðkomandi stofnunar sem hefur þetta viðskeyti. Engar vefþjónustur eru skráðar í þetta undirkerfi.

Fyrirsjáanlega mun vera algengast að sýsla með þau undirkerfi sem eru nefnd með viðskeytunum hér að ofan. Tvö önnur viðskeyti tilheyra nafnavenjum Straumsins:

* \<stofnun / kerfisflokkur>**-Private** Vefþjónustur sem ekki er æskilegt að birtist opinberlega í leitar- og uppflettiviðmóti vörulista vefþjónusta er hægt að skrá í undirkerfi nefnd með viðskeytinu „-Private“. Vefþjónustur sem eru skráðar í undirkerfi með þessu viðsketi (private) verða ekki birtar sjálfkrafa í vörulista vefþjónusta.&#x20;
* \<stofnun / kerfisflokkur>**-Public** Vefþjónustur sem hvort tveggja er æskilegt að birtist í vörulista fyrir þjónustur aðgengilegar á Straumnum, sem og í lista yfir vefþjónustur aðgengilegar almenningi í vefþjónustugátt Stafræns Íslands, er hægt að skrá í undirkerfi með viðskeytið „-Public“ í nafni.

Stofnun getur haft fleiri en eitt undirkerfi með hverju viðskeyti: Ef til dæmis stofnun heldur utan um tvo ólíka flokka vefþjónusta, þá mætti velja að skrá vefþjónusturnar í tvö undirkerfi, hvort með viðskeytinu „-Protected“. Dæmi:

skatturinn-vsk-protected\
skatturinn-stadgreidsla-protected\
skattturinn-fyrirtaekjaskra-protected

Nafnavenjur Straumsins eru óháðar stafsetum (e. case insensitive). Undirkerfi getur til dæmis verið nefnt: island-is-client.

Ef ekkert af ofangreindum viðskeytum eru í nafni undirkerfis, þá fara vefþjónustur þess að sjálfgefnu í vörulista vefþjónusta.

### Skráning vefþjónustu

Vefþjónustur eru skráðar innan undirkerfis með því að velja *Services* flipann undir *Clients* flipanum. Þar undir eru hnappar til að skrá annað hvort REST eða SOAP (WSDL) vefþjónustur:

![](/files/-MSCYSQBT3vOU1nVnOwK)

Við skráningu á REST vefþjónustu þarf að gefa upp nafn vefþjónustunnar, eða endapunktsins, *Service Code* (nöfn endapunkta koma sjálfkrafa inn tilfelli SOAP þjónusta út frá WSDL skilgreiningu). Nafnavenja er að Service Code endi á „-vN“ þar sem N er viðkomandi útgáfunúmer þjónustunnar, til dæmis: fasteignaskra-v1.

![](/files/-MSCYSQMY2FQzm15E585)

**Virkjun vefþjónustu**

Þegar vefþjónusta hefur verið skráð, þá þarf að virkja hana sérstaklega, með því að smella á rofa við skráningu vefþjónustunnar. Með þessum rofa er þá líka hægt að taka afvirkja vefþjónustur, t.d. vegna viðhalds, og þá svarar X-Road öryggisþjónnin með *Out of Order* skilaboðum við beiðnum til vefþjónustunnar.

![](/files/-MSCYSQWUMz_6xqsAw4I)

### Aðgangsheimildir að vefþjónustum eða stökum endapunktum

Aðgangsstýringu einstakra vefþjónusta er hægt að nálgast með því að smella á nafn vefþjónustu, *Service Code,* undir *Services* flipa viðkomandi undirkerfis:

![](/files/-MSCYSQy1h7XSLNnGrR7)

Á skráningarskjá vefþjónustunnar er að finna hnappinn *Add Subjects*:

![](/files/-MSCYSR7Y5S_u1OAdzMM)

*Add Subjects* hnappurinn sprettir upp leitarglugga þar sem er hægt að finna þau undirkerfi sem skal veita aðgang að vefþjónustunni:

![](/files/-MSCYSRLRTvM7v44lrXb)

Á skráningarsíðu vefþjónustunnar, undir *Access Rights*, má sjá lista þeirra undirkerfa sem hefur verið veittur aðgangur:

![](/files/-MSCYSRWPJvROba9imHg)

Í tilfelli REST vefþjónusta sem hafa verið skráðar með OpenAPI 3 skilgreiningu, þá er að finna *Endpoints* flipa á skráningarsíðu þeirra, þar sem má sjá yfirlit yfir allar aðgerðir vefþjónustunnar ásamt möguleika á að skilgreina aðgangsheimildir hverrar aðgerðar fyrir sig, með sambærilegum hætti og er gert fyrir vefþjónustur í heild:

![](/files/-MSCYSRYceKWxGbnlzYk)

![](/files/-MSCYSRZ9VN96omzVpI9)

Yfirlit annarra undirkerfa sem hafa aðgang að vefþjónustum viðkomandi undirkerfis er hægt að sjá undir flipanum *Service Clients* á upplýsingasíðu þess:

![](/files/-MSCYSR_6eNw_nvwUxjs)

Þar er einnig að finna *Add Subject* hnapp, sem má nota til að veita öðrum undirkerfum aðgangsheimild að vefþjónustuendapunktum þessa undirkerfis:

![](/files/-MSCYSRasvgRD_E9WZ4K)

![](/files/-MSCYSRb_0U1Yq1z2nmk)

### Local Groups

Á upplýsingaskjá undirkerfis, undir *Clients* flipanum, er að finna undirflipann *Local Groups*. Þar er hægt að safna saman í einn hóp þeim undirkerfum annarra aðila sem skal veita tilteknar aðgangsheimildir. Þannig er hægt að veita hópnum sem slíkum aðgangsheimild og öllum undirkerfum skráðum innan hans veitist þá heimildin. Þannig sparast vinna og flækjustig sem felst í því að veita hverju undirkerfi fyrir sig aðgangsheimildir.

Þegar hópur hefur verið búinn til:

![](/files/-MSCYSRjsZEWYgsiYlYz)

Þá er hægt að smella á nafn hópsins:

![](/files/-MSCYSRsErB1GJ47CLV-)

* til að opna skráningarskjá hópsins, þar er smellt á *Add Members* hnappinn til að bæta við þeim undirkerfum sem skulu öðlast þær aðgangsheimildir sem verða veittar hópnum:

![](/files/-MSCYSRyzD8GSwEoOyyP)

![](/files/-MSCYSS6481wfh7GJp7F)

![](/files/-MSCYSSDgagPyHEirQwA)

Þegar aðgangsheimildir eru veittar að undirkerfi, þá er hægt að velja hóp, eins og stök undirkerfi væru annars valin:

![](/files/-MSCYSSK55fWJwngkDst)

![](/files/-MSCYSSL3-TxhppSe5PP)

* Sjá nánar í [Local Access Right Groups](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) kafla notendahandbókar X-Road.

### Management API

Allar aðgerðir sem er mögulegt að framkvæma í umsýsluviðmóti (Admin UI) X-Road öryggisþjóns er einnig hægt að framkvæma með köllum í umsýslu-vefþjónustuskil – X-Road Management REST APIs. Í raun nýtir umsýsluviðmótið sér þessi vefþjónustuskil.

* Sjá nánar í [Management REST APIs](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) kafla í notendahandbók X-Road.

Hjá [Digital and Population Data Services Agency](https://dvv.fi/en) í Finnlandi er í þróun svokallað [X-Road toolkit](https://github.com/nordic-institute/X-Road-Security-Server-toolkit), sem er ætlað að auðvelda notkun þessara forritunar-skila við stillingu X-Road þjóna. Áætlað er að *X-Road toolkit* verði aðgengilegt í janúar 2021.

* Sjá [kynningu á X-Road toolkit](https://vimeo.com/461279848) (4:27:31).

### Kröfur til vefþjónusta sem tengjast Straumnum

Samskipti við vefþjónustur yfir Strauminn með X-Road fara að flestu leyti fram með sama hætti og þegar um bein köll í vefþjónustur er að ræða. Þar er helst um eina undartekningu að ræða sem felst í að vefþjónustuköll þurfa að innihalda upplýsingar í haus um viðkomandi undirkerfi: Köll í REST þjónustur þurfa að innihalda upplýsingar um það undirkerfi sem á frumkvæði að samskiptunum (*client)* í HTTP haus og köll í SOAP þjónustur þurfa að tiltaka bæði upplýsingar um undirkerfi biðlara og undirkerfi upplýsingaveitanda í SOAP haus, sem viðkomandi SOAP þjónusta þarf að skila óbreyttum til baka í svörum.

Nánar má lesa um samskiptastaðla milli upplýsingakerfa og X-Road öryggisþjóna í X-Road skjölun:

* X-Road: Message Protocol v4.0 <https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-mess_x-road_message_protocol.md>
* X-Road: Message Protocol for REST <https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-rest_x-road_message_protocol_for_rest.md>

Nánar um þetta má lesa í kafla 3 - *Útfærsla og aðlögun vefþjónusta fyrir Strauminn*.

## Útfærsla og aðlögun vefþjónusta fyrir Strauminn

### Umhverfin þrjú: IS-DEV, IS-TEST og IS

Eitt umhverfi Straumsins samanstendur af miðlægum þjónustum X-Road – skilríkjamiðstöð, tímastimplun, skráning og eftirlit – og öllum þeim öryggisþjónum stofnana sem hafa verið skráðir í miðlægu þjónustuna. Eitt slíkt umhverfi er einnig kallað *X-Road instance*.

Umhverfi Straumsins eru þrjú: „IS-DEV“, fyrir þróun, „IS-TEST“, fyrir prófanir með raungögnum, og raunumhverfið heitir „IS“.

![](/files/-MSCYSSMwb4Jdjnnh9Oy)

Innan hvers umhverfis er meðlimum skipt í flokka, eftir eðli stofnana:

* GOV fyrir opinberar stofnanir
* EDU fyrir menntastofnanir
* COM fyrir einkaaðila

Innan hvers flokks er meðlimum úthlutað kóða – *Member Code* – sem í þróunarumhverfinu (IS-DEV) er raðtala en kennitala viðkomandi aðila í hinum umhverfunum tveimur (IS-TEST og IS). Hver meðlimur skráir svo sín undirkerfi – *Subsystem* – eftir þörfum, fyrir biðlara (\*-Client) og upplýsingaveitur (\*-Protected), eins og áður hefur verið lýst ([2.2](https://app.gitbook.com/@origo/s/xroad-skjoelun/~/drafts/-MOk_6o9JK0bPAJLuFSB/untitled-2#nafnavenjur-straumsins-og-skraning-vefthjonusta-i-viskuausuna)).

Samsetning flokksheita, kóða meðlima og nafna undirkerfa mynda einskonar stigveldistré eða slóðir innan X-Road umhverfis Straumsins. Það má líta á þessar slóðir sem heimilisföng innan Straumsins, sem X-Road notar til að finna viðkomandi öryggisþjóna, upplýsingaveitur og biðlara.

![](/files/-MSCYSSOTtv99gwnVqKV)

### Hverskonar gögn eiga heima í hverju umhverfi

IS-DEV umhverfi Straumsins er ætlað fyrir þjónustur í þróun og er eingöngu ætlað fyrir flutning þróunargagna.

IS-TEST umhverfið má nýta til prófana á vefþjónustum sem eru hæfar í rekstur, með raungögnum.

IS er svo raunumhverfið, þar sem opinber samsktipti eiga sér stað.

### Kröfur fyrir vefþjónustur sem tengjast Straumnum

Smíði vefþjónusta fyrir Strauminn skal fylgja [REST höguninni](https://en.wikipedia.org/wiki/Representational_state_transfer) og vera lýst með OpenAPI 3.0 skilum. Við útfærslu vefþjónusta má styðjast við [*API Design Guide*](https://github.com/island-is/handbook/blob/master/docs/api-design-guide/README.md) frá Stafrænu Íslandi.

Mikill fjöldi vefþjónusta er þegar til staðar hjá hinum ýmsu stofnunum og fyrirtækjum og eðlilega fylgja þær ekki nýtilkomnum hönnunar- og útfærsluleiðbeiningum frá Stafrænu Íslandi. Margar fyrirliggjandi vefþjónustur fylgja til dæmis SOAP samskiptareglunum. Lögð er áhersla á að þessar vefþjónustur nýtist í Straumnum, jafnvel án breytinga þar sem því verður við komið. Nánar er fjallað um möguleika í því samhengi í eftirfarandi undirköflum.

### Tenging og aðlögun REST vefþjónusta

Auðveldast er að skrá REST vefþjónustur í Strauminn, til dæmis með því að skrá inn slóð að OpenAPI 3.0 skilum, eins og er lýst í kafla 2.3 Skráning vefþjónustu, eða með því að skrá inn grunnslóð að endapunkti vefþjónustunnar.

REST vefþjónustur nýtast óbreyttar í Straumnum yfir X-Road en tvær einfaldar breytingar blasa við kerfum, sem senda beiðnir til REST þjónusta yfir X-Road, t.d. öðrum vefþjónustum í formi biðlara. Þessar breytingar snúa að auðkenni undirkerfa biðlara og upplýsingaveitanda – *Instance Identifier, Member Class* og *Member Code* – sbr. stigveldistré sem er lýst í kafla 3.1 *Umhverfin þrjú: IS-DEV, IS-TEST og IS*:

* Með beiðni þarf að senda HTTP hausinn *X-Road-Client*, með gildi sem inniheldur auðkenni undirkerfis biðlarans, t.d. „**IS/GOV/5501692829/island-is-client**“.
* Framan við grunnslóð vefþjónustuveitunnar bætist auðkenni þess undirkerfis sem hýsir hana: Ef óbreytt kall í vefþjónustuna væri eftir slóðinni GET /api/SearchBySocialID/0304756079 og vefþjónustan er skráð í X-Road undirkerfi, þar sem *Instance Identifier*: **IS** *Member Class*: **COM** *Member Code*: **5302922079** *Subsystem*: **Origo-Protected** þá yrði slóðin yfir X-Road: GET /r1/**IS**/**COM**/**5302922079**/**Origo-Protected**/api/SearchBySocialID/0304756079

Sjá nánar í [X-Road: Message Protocol for REST](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-rest_x-road_message_protocol_for_rest.md).

### Dæmi um kall í REST vefþjónustu yfir X-Road

cURL dæmi um kall í vefþjónustu yfir X-Road, þar sem biðlari og þjónustuveita eru skráð eins og í dæmi í 3.2.1:

```python
curl --location --request GET 'http:// securityserver.island.internal/r1/IS/COM/5302922079/Origo-Protected/api/SearchBySocialID/0304756079' \
--header 'X-Road-Client: IS/GOV/5501692829/island-is-client'
```

#### Tenging og aðlögun SOAP vefþjónusta

Skráning WSDL lýsingar fyrir SOAP þjónustur í X-Road er ein og sér auðveld: Lýsing endapunktanna skilar sér sjálfkrafa inn og það er hægt að stýra aðgangi að hverjum þeirra með svipuðum hætti og er lýst í 2.4 *Aðgangsheimildir að vefþjónustum eða stökum endapunktum*.

SOAP þjónustur beintengdar við X-Road þjón nýtast þó ekki óbreyttar, þar sem þær þurfa að skila í svörum þeim X-Road gildum sem nauðsynlega berast í haus SOAP skeyta. Til að komast undan sértækri X-Road aðlögun SOAP þjónusta má notast við einskonar millistykki, sem liggur á milli X-Road þjóns og vefþjónustu, handlangar beiðnir á milli þeirra og sér til þess að gildum í SOAP haus beiðnar sé skilað með sama hætti í svari. Nánar um slíkt millistykki er fjallað í 3.2.3.1 *SOAP headers adaptor*.

Haus í SOAP skeyti þarf að innihalda sambærilegar upplýsingar og var lýst fyrir REST samskipti í 3.2.1, um auðkenni undirkerfa biðlara og upplýsingaveitanda. Sömu upplýsingar og voru tilteknar í REST dæminu að ofan, kæmu fram með eftirfarandi hætti í haus SOAP skeytis:

```xml
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:xrd="http://x-road.eu/xsd/xroad.xsd"
   xmlns:id="http://x-road.eu/xsd/identifiers"
>
  <SOAP-ENV:Header>
    <xrd:protocolVersion>4.0</xrd:protocolVersion>
    <xrd:id>3903d152-1d2c-11eb-adc1-0242ac120002</xrd:id>
    <xrd:userId>anonymous</xrd:userId>
    <xrd:service id:objectType="SERVICE">
      <id:xRoadInstance>IS</id:xRoadInstance>
      <id:memberClass>COM</id:memberClass>
      <id:memberCode>5302922079</id:memberCode>
      <id:subsystemCode>Origo-Protected</id:subsystemCode>
      <id:serviceCode>sendMessage</id:serviceCode>
      <id:serviceVersion>1</id:serviceVersion>
    </xrd:service>
    <xrd:client id:objectType="SUBSYSTEM" >
      <id:xRoadInstance>IS</id:xRoadInstance>
      <id:memberClass>GOV</id:memberClass>
      <id:memberCode>5501692829</id:memberCode>
      <id:subsystemCode>island-is-client</id:subsystemCode>
    </xrd:client>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <sendMessage ...>
      ...
    </sendMessage>
  </SOAP-ENV:Body>
...
```

Gildi serviceCode í haus verður að vera það sama og heiti XML tags sem hjúpar [beiðnina](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-mess_x-road_message_protocol.md) (2.3 Message Body).

Með serviceVersion er hægt að vísa til [útgáfu vefþjónustu í WSDL skilgreiningu](https://github.com/nordic-institute/xrd4j/blob/develop/example-adapter/src/main/resources/example.xroad-6.4.wsdl) (\<xrd:version>v1\</xrd:version>).

Svar frá SOAP vefþjónustu þarf að innihalda sömu X-Road upplýsingar og komu inn í skeytahaus beiðnar, í sömu röð.

Sjá nánar í [X-Road: Message Protocol v4.0](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-mess_x-road_message_protocol.md).

**SOAP headers adaptor**

Til að komast hjá aðlögun fyrirliggjandi SOAP vefþjónusta að þeim kröfum sem fylgja samskiptum við X-Road öryggisþjóna, sem er lýst í 3.2.3 *Tenging og aðlögun SOAP vefþjónusta*, má styðjast við einskonar millistykki, eða *proxy / adaptor*, sem handlangar beiðnir milli X-Road þjóns og SOAP vefþjónustu, og sér til þess að X-Road gildi í SOAP haus beiðnar skili sér einnig til baka í SOAP haus svarskeytis frá vefþjónustu.

Hýsingarvélar X-Road þjóna, sem hafa verið settar upp með aðstoð Stafræns Íslands / Origo, keyra eina útgáfu af slíku millistykki og með það til staðar er nóg að setja `„localhost:5443/“` fyrir framan nafn hýsils viðkomandi vefþjónustu, þegar um HTTPS samskipti er að ræða, og `„localhost:5080/“` fyrir framan *host*-nafn vefþjónustunnar í tilfelli ódulkóðaðra HTTP samskipta.

![](/files/-MSCYSSULrq0tU0I-_No)

**REST adaptor service**

Í mörgum tilfellum getur biðlari átt í REST samskiptum yfir X-Road þó svo að á hinum endanum standi SOAP vefþjónusta fyrir svörum. Þetta er gert mögulegt með svokölluðu [X-Road REST Adapter Service](https://github.com/nordic-institute/REST-adapter-service), sem einnig er uppsett á þeim X-Road hýsingarvélum sem Stafrænt Ísland / Origo hafa komið að (á porti 6080).

Undirkerfi upplýsingaveitu og heiti vefþjónustuendapunkts eru tiltekin á REST vefslóð, ásamt upplýsingum um XML nafnarými (e. namespace) viðkomandi þjónustu. Dæmi um REST kall í vefþjónustu sem er hýst í undirkerfi sem hefur komið fram í dæmum kaflanna hér á undan:

`http://localhost:6080/rest-adapter-service/Consumer/IS.COM.5302922079.Origo-Protected.CapitalCity/?sCountryISOCode=IS&X-XRd-NamespaceSerialize=http://www.oorsprong.org/websamples.countryinfo&X-XRd-NamespacePrefixSerialize=&Accept=application/json`

Þessi vörpun milli REST og SOAP er takmörkunum háð. Til dæmis er eins og er ekki stuðningur við að setja fram í REST kalli WS-Security auðkenningarhaus fyrir SOAP vefþjónustu.

### **Uppsetning X-Road REST og SOAP millistykkja**

Til að auðvelda uppsetningu þessara REST og SOAP millistykkja á hýsingarvélum X-Road þjóna, hafa verið settar saman [skriftur og skilgreiningar, ásamt leiðbeiningum](https://github.com/bthj/xroad-rest-soap-adapters), sem má nota til að setja millistykkin upp sem stýrikerfisþjónustur (þessar skriftur setja upp millistykkin með Docker og Docker Compose, sem er [ekki lengur stutt af RHEL](https://access.redhat.com/solutions/3696691), svo síðari útgáfa þessarar uppsetningar kann að [styðjast við](https://www.redhat.com/sysadmin/compose-podman-pods) [Podman](https://podman.io/)).

Með þessar tvær einingar til staðar má í mörgum tilfellum eiga í REST samskiptum við SOAP vefþjónustur, og í öllu falli tengja SOAP vefþjónustur við X-Road án þess að eiga frekar við þær.

Dæmi um samskiptaleið frá REST biðlara, til X-Road öryggisþjóns (SS1), til X-Road þjóns upplýsingaveitu (SS2), sem hýsir óbreytta SOAP þjónustu, má stilla upp svona:

REST <-> REST-adaptor-service <-> X-Road SS1 <-> X-Road SS2 <-> universal-xroad-soap-proxy <-> legacy SOAP service

![](/files/-MSCYSSYPyEcdHofrH1s)

Með þessari uppsetningu keyrir REST millistykkið á porti 6080 hýsingarvélarinnar og SOAP millistykkið handlangar HTTP beiðnir á 5080 og HTTPS á 5443.

### Samband öryggisþjóna við upplýsingakerfi

Þrenns konar samskiptamátar koma til greina milli X-Road öryggisþjóns og þeirra (innri) upplýsingakerfa / vefþjónusta sem hann svarar fyrir:

Ef samskiptaleið milli öryggisþjóns og innri vefþjónustu liggur yfir innan sama örugga netlagsins, þá kann vera talið öruggt að notast við ódulkóðuð HTTP samskipti.

Sé samskiptaleiðin yfir ótrygg net, þá er rétt að notast við HTTPS samskiptaregluna með gagnkvæmri auðkenningu (mTLS), sem er sjálfgefni valkosturinn, eða án auðkenningar, sem er síður mælt með.

Þessar stillingar er að finna í umsýsluviðmóti öryggisþjóns undir *Internal Servers* flipa viðkomandi undirkerfis. Þar, undir *Information System TLS certificate*, er hægt að flytja inn opinberan skírteinishluta viðkomandi upplýsingakerfis. Undir *Security Server certificate* er hægt að flytja út opinberan skírteinishluta X-Road öryggisþjónsins, til handa þeim upplýsingakerfum sem vilja eiga í gagnkvæmt auðkenndum samskiptum við þjóninn.

![](/files/-MSCYSSgVTJpiHlHAVVP)

TLS lykil öryggisþjónsins er einnig að finna í umsýsluviðmótinu undir *Keys and Certificates -> Security Server TLS Key*.

![](/files/-MSCYSSsaTpfyni1QSes)

Eftirfarandi er dæmi um beiðni frá upplýsingakerfi til öryggisþjóns, í formi *curl* skipunar:

```python
curl --cert dev-island-is_client.crt --key dev-island-is_client.key --cacert dev-island-is_ss.pem -H "X-Road-Client: IS-DEV/GOV/10000/island-is-client" https://ss_dev01:8443/r1/IS-DEV/COM/10002/Origo-Protected/APIS/company?name=nemur
```

`dev-island-is_client.crt` og `dev-island-is_client.key` eru skírteini upplýsingakerfisins / vefþjónustunnar sem sendir beiðni X-Road öryggisþjóns á eigin vegum, og `dev-island-is_ss.pem` stendur fyrir skírteini öryggisþjónsins.

Skírteini með eigin undirskrift fyrir upplýsingakerfið (*curl* skipunina) í dæminu hér að ofan má til dæmis útbúa með eftirfarandi skipunum:

**create-self-signed-cert.sh**

```python
#!/bin/sh
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
openssl rsa -passin pass:x -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 7300 -in server.csr -signkey server.key -out server.crt
```

eða

```python
sudo openssl req -nodes -new -x509 -days 7300 \
-keyout server.key \
-out server.crt \
-subj "/C=ST/O=Local/CN=localhost"
```

Sjá nánar í kaflanum [Communication with the Client Information Systems](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) í notendahandbók X-Road öryggisþjóna.

### Aðgreining aðgangs að undirkerfum

Þegar ólík upplýsingakerfi hafa aðgang að sama X-Road öryggisþjóni en það er ekki æskilegt að hvert þeirra hafi sama aðgang að öllum þeim undirkerfum sem öryggisþjónninn hýsir, þá er ofangreind mTLS samskipti leið til aðgreiningar heimilda hvers upplýsingakerfis að X-Road undirkerfum.

Tökum sem dæmi tvö upplýsingakerfi, **A** og **B** (t.d. tvö aðskilin GraphQL lög), sem vilja senda beiðnir út á Strauminn. Þessi tvö upplýsingakerfi hafa aðgang að X-Road öryggisþjóni sem hýsir tvö *client* undirkerfi:

island-is-minar-sidur-client

* sem hefur heimild til að framkvæma beiðnir til vefþjónusta hjá Þjóðskrá

island-is-ytri-vefur-client

* sem hefur ekki aðgangsheimild að vefþjónustum Þjóðskrár

Upplýsingakerfi **A** hefur það hlutverk að kalla til Þjóðskrár í gegnum island-is-minar-sidur-client undirkerfið en upplýsingakerfi **B** á ekki að hafa heimild til þess.

Leið til þessarar aðgreiningar er að upplýsingakerfi **A** og undirkerfið island-is-minar-sidur-client skiptist á skírteinum til að koma á gagnkvæmu trausti; mTLS sambandi. Að sama skapi geta upplýsingakerfi **B** og undirkerfið island-is-ytri-vefur-client skipts á skírteinum.

Með þessu fyrirkomulagi getur upplýsingakerfi **B** ekki framkvæmt köll í gegnum undirkerfið island-is-minar-sidur-client og þar með öðlast aðgangsheimildir sem því hefur verið veitt.

### Aðgangur að X-Road þróunarumhverfi Ísland.is

Til að eiga samskipti við vefþjónustur yfir Strauminn í þróunarumhverfi Ísland.is (dev), þá þarf AWS SSO aðgangsheimildir að því umhverfi og fylgja eftirfarandi skrefum:

1. Taka afrit af umhverfisbreytum (environment variables) úr AWS SSO og setja í console
2. Keyra `aws eks update-kubeconfig --name dev-cluster01 --region eu-west-1` ([skrifar að sjálfgefnu í \~/.kube/config](https://docs.aws.amazon.com/cli/latest/reference/eks/update-kubeconfig.html))
3. Keyra `kubectl -n socat port-forward svc/socat-xroad 8080:80` svo umferð sé áframsend frá porti 8080 á þróunarvél (localhost:8080) að porti 80 á X-Road öryggisþjóni Ísland.is.

AWS SSO aðgangsheimildir eru veittar af DevOps umsjónaraðila Stafræns Íslands: [Andes](https://andes.is).

Með ofangreindum aðgangi að X-Road þjóni Ísland.is er hægt að lista upp þau undirkerfi (subsystem) sem eru skráð í viðkomandi X-Road umhverfi (IS-DEV instance), með skipun eins og:

```
curl ‘http://localhost:8080/listClients’
```

#### Öflun upplýsinga um undirkerfi og vefþjónustur innan þeirra

* REST

  Til að fá upplýsingar um vefþjónustur innan undirkerfis má gefa skipun eins og:

  ```
  curl -H ‘X-Road-Client: IS-DEV/GOV/10000/island-is-client’ ‘http://localhost:8080/r1/IS-DEV/provider-member-class/provider-member-code/provider-subsystem-name/listMethods’ | json_pp
  ```

  Ef vefþjónusta býður upp á OpenAPI 3 skil, þá er hægt að nálgast þau yfir X-Road með skipun eins og:

  ```
  curl -H ‘X-Road-Client: IS-DEV/GOV/10000/island-is-client’ ‘http://localhost:8080/r1/IS-DEV/provider-member-class/provider-member-code/provider-subsystem-name/getOpenAPI?serviceCode=provider-service-code’
  ```
* SOAP

  Upplýsingar um SOAP endapunkta innan undirkerfis er hægt að sækja með skipun eins og:

  ```
  curl --location --request POST 'http://localhost:8080/' --header 'Content-Type: text/xml;charset=UTF-8' --data @SJUKRA-protected-allowedMethods-fra-island-is.xml
  ```

  þar sem skráin `SJUKRA-protected-allowedMethods-fra-island-is.xml` getur innihaldið:

  ```xml
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:isl="http://islandrg.service.mule.tr.is/" xmlns:xrd="http://x-road.eu/xsd/xroad.xsd" xmlns:id="http://x-road.eu/xsd/identifiers">
     <soapenv:Header>
        <xrd:protocolVersion>4.0</xrd:protocolVersion>
        <xrd:id>3903d152-1d2c-11eb-adc1-0242ac120002</xrd:id>
        <xrd:userId>anonymous</xrd:userId>
        <xrd:service id:objectType="SERVICE">
            <id:xRoadInstance>IS-DEV</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>10007</id:memberCode>
            <id:subsystemCode>SJUKRA-Protected</id:subsystemCode>
            <id:serviceCode>allowedMethods</id:serviceCode>
        </xrd:service>
        <xrd:client id:objectType="SUBSYSTEM">
            <id:xRoadInstance>IS-DEV</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>10000</id:memberCode>
            <id:subsystemCode>island-is-client</id:subsystemCode>
        </xrd:client>
     </soapenv:Header>
     <soapenv:Body>
        <xrd:allowedMethods/>
     </soapenv:Body>
  </soapenv:Envelope>
  ```

  WSDL skil SOAP þjónustu er hægt að sækja yfir X-Road með skipun eins og:

  ```
  curl --location --request POST 'http://localhost:8080/' --header 'Content-Type: text/xml;charset=UTF-8' --data @SJUKRA-protected-getWsdl-fra-island-is.xml
  ```

  þar sem skráin `SJUKRA-protected-getWsdl-fra-island-is.xml` getur innihaldið:

  ```xml
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:isl="http://islandrg.service.mule.tr.is/" xmlns:xrd="http://x-road.eu/xsd/xroad.xsd" xmlns:id="http://x-road.eu/xsd/identifiers">
     <soapenv:Header>
        <xrd:protocolVersion>4.0</xrd:protocolVersion>
        <xrd:id>3903d152-1d2c-11eb-adc1-0242ac120002</xrd:id>
        <xrd:userId>anonymous</xrd:userId>
        <xrd:service id:objectType="SERVICE">
            <id:xRoadInstance>IS-DEV</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>10007</id:memberCode>
            <id:subsystemCode>SJUKRA-Protected</id:subsystemCode>
            <id:serviceCode>getWsdl</id:serviceCode>
        </xrd:service>
        <xrd:client id:objectType="SUBSYSTEM">
            <id:xRoadInstance>IS-DEV</id:xRoadInstance>
            <id:memberClass>GOV</id:memberClass>
            <id:memberCode>10000</id:memberCode>
            <id:subsystemCode>island-is-client</id:subsystemCode>
        </xrd:client>
     </soapenv:Header>
     <soapenv:Body>
       <xrd:getWsdl>
           <xrd:serviceCode>profun</xrd:serviceCode>
       </xrd:getWsdl>
     </soapenv:Body>
  </soapenv:Envelope>
  ```

  Nánari upplýsingar er að finna í: [X-Road: Service Metadata Protocol - Annex B listMethods, allowedMethods, and getWsdl service descriptions](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-meta_x-road_service_metadata_protocol.md#annex-b-listmethods-allowedmethods-and-getwsdl-service-descriptions)
* API Catalog\
  Þessar upplýsingar eru einnig aðgengilegar í vefviðmóti Viskuausunnar, *API Catalog* Stafræns Íslands \[TODO: hlekkur].

## Uppsetning og rekstur X-Road öryggisþjóna í Straumnum

### Uppsetning og uppfærsla

Uppsetning X-Road byggir á Linux hugbúnaðarpökkum, sem eru útbúnir fyrir Ubuntu (18.04 LTS) og Red Hat (RHEL 7 og 8) dreifingarnar. Séríslensk afbrigði þessara hugbúnaðarpakka skulu notuð við uppsettningu þjóna sem tengjast Straumnum. Upplýsingar um net- og vélbúnaðarkröfur, uppsetningar- og skráningarskref fyrir X-Road öryggisþjóna er að finna í skjalinu *Straumurinn – Security Server installation and registration steps*.

Útgáfur uppsettra öryggisþjóna skulu ekki vera meira en tveimur útgáfunúmerum á eftir nýjustu útgáfu X-Road hverju sinni.

Í því keyrsluumhverfi sem er mælt með fyrir X-Road öryggisþjóna í rekstri – uppsetningar út frá stýrikerfispökkum í stað [gámauppsetninga](https://github.com/nordic-institute/X-Road-Security-Server-sidecar), sem verða þó í framtíðinni (2021) rekstrarhæfar – felst uppfærsla yfirleitt í því að uppfæra viðkomandi stýrikerfispakka. Í sumum tilfellum kann að vera nauðsynlegt að framkvæma handvirk skref, eins og aðlögun gagnagrunns. Ávallt skal gaumgæfa [útgáfulýsingar](https://confluence.niis.org/display/XRDKB/Release+Notes) áður en uppfærsla er framkvæmd, sérstaklega þegar um breytingar á megin-útgáfu er að ræða.

Nánara lesefni:

* [How to Set Up a Security Server?](https://confluence.niis.org/pages/viewpage.action?pageId=4292920)
  * sjá dæmi um uppfærsluskipanir í þessu yfirskjali
* [X-Road Knowledge Base](https://confluence.niis.org/display/XRDKB/X-Road+Knowledge+Base)
* [Sértæk skref við uppsetningu og þáttöku í Straumnum](https://github.com/digitaliceland/Straumurinn)

### Rekstur

X-Road er opinn hugbúnaður og án leyfisgjalda.

Rekstur miðlægra þjónusta Straumsins – skilríkjamiðstöðvar og miðlægrar skráningar – er á vegum Stafræns Íslands meðan stofnanir sjá um rekstur sinna öryggisþjóna:

* Hýsing, eftirlit og rekstur á Linux þjónum
* Ef Red Hat stýrikerfið (RHEL) er valið, þá felur það í sér leyfisgjöld, meðan Ubuntu, sem einnig er stutt, er án þeirra
* Rekstraraðili X-Road öryggisþjóns þarf að fylgjast með honum og uppfæra reglulega
* Endurnýjun skilríkja, þar sem þarf að óska eftir nýjum frá skilríkjamiðstöð Straumsins

Net-opnanir eru skjalaðar í uppsetningarleiðbeiningum og eftirfarandi mynd sýnir yfirlit þeirra til glöggvunar:

![](/files/-MSCYSSxGPi6UqS6_2sL)

### Högun tiltækileika

Meðal kosta við við dreifða högun X-Road er að engin ein eining er kerfislægur flöskuháls eða uppspretta bilunar. Tiltækileika öryggisþjónustu fyrir hverja upplýsingaveitu og -biðlara er hægt að auka með tilhögun umfremdar (e. redundant configuration). Tvær leiðir eru mögulegar til að auka tiltækileika X-Road öryggisþjóna: Innri og ytri álagsdreifing. Val milli þessara leiða felst í málamiðlun milli einfaldleika og sveigjanleika.

X-Road öryggisþjónar búa yfir innbyggðum eiginleika til álagsdreifingar fyrir biðlara, ásamt því að styðja ytri álagsdreifingu. Innbyggð álagsdreifing fyrir biðlara veitir háan tiltækileika. Stuðningur við ytri álagsdreifingu veitir hins vegar hvort tveggja háan tiltækileika og aukin afköst, sem skalanleg högun.

### Innbyggð álagsdreifing

Innbyggð álagsdreifing er eiginleiki byggður inn í X-Road öryggisþjóna. Eiginleikinn veitir háan tiltækileika en ekki skalanleika, þar sem sömu þjónustur geta verið skráðar á marga öryggisþjóna, sem verða fyrir valinu eftir því hver verður fyrstur fyrir svörum. Ef sama þjónusta er tiltæk frá mörgum öryggisþjónum, þá er beiðnum til þjónustunnar dreift milli þjónanna en álaginu er ekki skipt jafnt milli þjónanna sem svara fyrir sömu upplýsingaveituna. Ef einn öryggisþjónanna aftengist, þá er beiðnum sjálfkrafa beint að öðrum tiltækum þjónum. Öryggisþjónn biðlara mun velja þann öryggisþjón upplýsingaveitu sem verður fyrstur til að svara. Þannig er umfremd innifalin í samskiptareglur milli öryggisþjóna ([X-Road message transport protocol](https://github.com/nordic-institute/X-Road/blob/develop/doc/Protocols/pr-messtransp_x-road_message_transport_protocol.md)), svo fremi sem fleiri en einum öryggisþjóni er stillt upp fyrir þjónustur.

Uppsetning innri álagsdreifingar er einfaldari en ytri álagsdreifing, þar sem öryggisþjónarnir sjá innan kerfis um beiningu beiðna og sannprófun skilríkja. Slík uppsetning krefst þó þess að þjónustur séu skráðar eins hjá hverjum öryggisþjóni um sig; þegar nýrri þjónustu er bætt við þarf að sjá til þess að hún sé skráð sérstaklega á alla þá öryggisþjóna sem er ætlað að svara fyrir hana. Hver öryggisþjónn í slíkri uppsetningu þarf að hafa farið í gegnum sjálfstætt skráningarferli í miðlæga þjónustu Straumsins.

![](/files/yjRYRrt4TGM0RTXLBde2)

Fyrstur til svara vinnur: Sá öryggisþjónn sem nær fyrst að koma á TCP tengingu (SS1, SS2 eða SS3) verður fyrir vali öryggisþjóns biðlara (SS).

### Ytri álagsdreifing

Hvort tveggja háan tiltækileika og aukin afköst er hægt að ná með því að nýta stuðning X-Road öryggisþjóna við ytri álagsdreifingu (e. load balancer) sem snýr að Internetinu. Í slíkri högun er lausn til álagsdreifingar (LB) sett fyrir framan klasa öryggisþjóna og skeytum sem berast er dreift milli þjóna klasans, samkvæmt því reikniriti álagsdreifingar sem er valið að styðjast við. Með vöktunarskilum öryggisþjóna (e. health check API) getur álagsdreifingin greint ef einingar innan klasans hætta að svara og þá hætt að beina umferð til þeirra.

Uppsetning klasa öryggisþjóna er flóknari í samanburði við nýtingu innri álagsdreifingar, sem er innbyggður eiginleiki og að sjálfgefnu virkur. Uppfærsla öryggisþjóna er flóknari með ytri álagsdreifingu, þar sem samræma þarf uppfærsluferlið innan klasans. Á hinn bóginn er auðveldara að bæta einingum við klasann, þar sem ekki þarf að fara í gegnum skráningarferlið gagnvart miðlægri þjónustu Straumsins fyrir hverja þeirra, því allar einingar klasans deila sama auðkenni. Til samanburðar, þá hefur hver öryggisþjónn sem tekur þátt í innri álagsdreifingu sitt eigið auðkenni, og þarf því að fara í gegnum sjálfstætt skráningarferli.

![](/files/-MSCYST1KulEdROilCSY)

Ytri álagsdreifingu er hægt að setja upp fyrir framan klasa af X-Road öryggisþjónum, þar sem er séð um að beina umferð milli eininga klasans.![](/files/-MSCYSTAWMvGMPq2TQLr)

Nánar má lesa í:

* [X-Road Architecture](https://x-road.global/architecture)
* [Balancing the Load in X-Road](https://www.niis.org/blog/2018/6/25/balancing-the-load)
* [X-Road Security Architecture: Availability](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-sec_x_road_security_architecture.md)
* [X-Road: Security Server Architecture: Redundant Deployment](https://github.com/nordic-institute/X-Road/blob/develop/doc/Architecture/arc-ss_x-road_security_server_architecture.md)
* [X-Road: External Load Balancer Installation Guide](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/LoadBalancing/ig-xlb_x-road_external_load_balancer_installation_guide.md)

### Umsýsluviðmót X-Road öryggisþjóns

Umsýsluviðmót X-Road öryggisþjóns (Security Server) er hægt að nálgast á slóð eins og:

**Error! Hyperlink reference not valid.**

þar sem \<innri-IP-tala/innra-host-nafn> er innra vistfang þjónsins á VPN- eða staðarneti, eingögu aðgengilegt viðkomandi starfsmönnum.

### Hlutverk notenda

Umsýsluviðmót (e. admin UI) X-Road öryggisþjóna veitir aðgang að helstu aðgerðum er lúta að daglegum rekstri þeirra, svo sem skráningu vefþjónusta, eins og var vikið að í kafla 2 - *Vefþjónustur í Straumnum*, og utanumhaldi skírteina. Hvaða aðgerðir eru sýnilegar notanda umsýsluviðmótsins er háð hvaða hlutverki henni hefur verið úthlutað. Hlutverkin eru skráð sem stýrikerfishópar og eru:

* **Security Officer** (xroad-security-officer), sýslar með lykla og skírteini.
* **Registration Officer** (xroad-registration-officer), heldur utan um skráningu undirkerfa.
* **Service Administrator** (xroad-service-administrator), skráir vefþjónustur og stýrir aðgangi að þeim.
* **System Administrator** (xroad-system-administrator), ber ábyrgð a uppsetningu, stillingum og viðhaldi öryggisþjóns.
* **Security Server Observer** (xroad-securityserver-observer), hefur lesaðgang að umsýsluviðmóti öryggisþjóns.

Hver notandi getur haft fleiri en eitt hlutverk og fleiri en einn notandi getur haft hvert hlutverk.

Sjá nánar í kaflanum [User Management](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) í notendahandbók X-Road öryggisþjóna.

### Afritun og endurheimt

Undir *Settings -> Backup and Restore* má sjá yfirlit þau afrit sem eru sjálfvirkt tekin daglega. Jafnframt er hægt að taka afrit handvirkt með því að smella á hnappinn *Back Up Config*, sem birtist þá einnig í listanum. Á þessum skjá er einnig hægt að hlaðainn afriti, t.d. á nýuppsettum þjóni.

Þessar aðgerðir er einnig hægt að framkvæma frá skipanalínu, eins og er vikið að í kafla 4.5.4 *Afrit*.

![](/files/-MSCYSTEsfuTOZ2RaMjl)

### Yfirlit kerfisstillinga

Yfirlit kerfisstillinga er að finna í umsýsluviðmótinu undir *Settings -> System Parameters*. Þar er að finna aðgerðir til að flytja inn og út *Configuration Anchor*, skrá með upplýsingum um miðlægar þjónustur í umhverfi Straumsins sem er hægt að sækja frá:

<https://github.com/digitaliceland/Straumurinn>

![](/files/-MSCYSTHalR0RPlRP4t4)

### Kerfisgreining

Undir *Diagnostics* flipa umsýsluviðmóts er að finna yfirlit yfir stöðu öryggisþjónsins gagnvart miðlægum þjónustum Straumsins:

* *Global configuration* sýnir hvort eintak öryggisþjónsins af víðværum stillingum Straumsins séu upp til dags, en í þeim er meðal annars að finna upplýsingar um aðra meðlimi Straumsins og þjónustur þeirra.
* *Timestamping* segir til um samband við miðlæga tímastimpil-þjónustu Straumsins.
* Öryggisþjónar nota miðlægu *OCSP Responders* þjónustuna til að sannprófa skilríki og hér má einnig sjá stöðu sambands við hana.

![](/files/-MSCYSTIDUj7puAL8kir)

### Auðkenningar- og undirskriftarlyklar

Lykla og skírteini fyrir auðkenningu í samskiptum milli öryggisþjóna og fyrir undirskrift skeyta er að finna í umsýsluviðmótinu undir *Keys and Certificates -> Sign and Auth Keys*. Þar er hægt að útbúa beiðnir um undirskrift (CSR) frá miðlægri umsýslu Straumsins, ásamt því að flytja inn undirrituð skírteini.

![](/files/-MSCYSTRj9dMcRifAUZw)

### API lyklar

Lykla sem veita aðgang að vélrænu umsýsluviðmóti öryggisþjóns – Management API – er hægt að útbúa undir *Keys and Certificates -> API Keys* í *Admin UI* öryggisþjóns. Þegar er valið að búa til nýjan lykil, birtist gluggi með vali um notendahlutverk, sem er lýst í 4.4.1 - *Hlutverk notenda*.

![](/files/-MSCYSTYpBHPZktQfXwZ)

### TLS lykill öryggisþjóns

Undir flipanum *Keys and Certificates* í umsýsluviðmóti öryggisþjóns er að finna upplýsingar um skírteini þjónsins, sem er hægt að nota í öruggum samskiptum við þau upplýsingakerfi sem hann svarar fyrir. Um þessi samskipti er fjallað í kafla 3.3 - *Samband öryggisþjóna við upplýsingakerfi*.

![](/files/-MSCYSTbsmQBksClq9El)

## Afritataka og vöktun

### Kerfisskrár

Kerfishlutar X-Road skrifa í logga undir `/var/log/xroad/*` . Mikilvægustu kerfishlutarnir og loggar þeirra eru:

* xroad-confclient, dreifir skráningarupplýsingum fyrir umhverfi Straumsins og skrifar í configuration\_client.log
* xroad-proxy, miðlar skeytum og skrifar í proxy.log
* xroad-signer, sýslar með lykla og skrifar í signer.log
* xroad-proxy-ui-api, skil fyrir umsýsluviðmót sem skrifa í proxy\_ui\_api.log og proxy\_ui\_api\_access.log

### Ræsing kerfishluta

Einstaka kerfishluta er hægt að ræsa með skipun eins og:

service \<nafn-kerfishluta> start

Sjá nánar í [Logs and System Services](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) kafla notendahandbókar X-Road öryggisþjóna.

### Samskiptaskrár

Samskipti milli X-Road öryggisþjóna er skráð í undirskrifuð og tímastimpluð skjöl ([Associated Signature Container](https://en.wikipedia.org/wiki/Associated_Signature_Containers)), fyrst í gagnagrunni en eru með reglulegum hætti flutt út í skráakerfi hýsingarvélar X-Road öryggisþjónsins, samkvæmt stillingum sem eru útlistaðar í [Message Log](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) kafla notendahandbókar fyrir öryggisþjóna.

Samskiptaskrárnar vistast í skráakerfi hýsingarvélarinnar, að sjálfgefnu undir\
`/var/lib/xroad`

Nánar um samskiptaskrárnar og skoðun þeirra má lesa í skjalinu:

* [Signed Document Download and Verification Manual](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-sigdoc_x-road_signed_document_download_and_verification_manual.md)

Séríslensk útgáfa X-Road hugbúnaðarpakka [afvirkjar skráningu á innihaldi skeyta](https://github.com/nordic-institute/X-Road/blob/develop/src/packages/src/xroad/default-configuration/override-securityserver-is.ini) sem eru send á milli upplýsingakerfa með hjálp X-Road öryggisþjóna. Ef ákvörðun liggur fyrir um að innihald skeyta skuli skráð – sem felur í sér frekari möguleika á staðfestingu þess að tiltekin samskipti hafi átt sér stað, en gerir einnig frekari kröfur um úttektir m.t.t. persónuverndarlöggjafar – þá er hægt að virkja slíka skráningu með eftirfarandi í skránni `/etc/xroad/conf.d/local.in`:

```python
[message-log]
message-body-logging=false
```

Sjá einnig almenna umfjöllun um X-Road skráningu í:

* X-Road Logs Explained – [Part 1](https://www.niis.org/blog/2018/5/27/x-road-logs-basics), [Part 2](https://www.niis.org/blog/2018/6/3/x-road-logs-explained-part-2) and [Part 3](https://www.niis.org/blog/2018/6/12/x-road-logs-explained-part-3)

### **Útflutningur samskiptaskráa af hýsingarvél**

Svo samskiptaskrár fylli ekki skráakerfi hýsingarvélar öryggisþjónsins er vert að sjá til þess að þær séu fluttar af vélinni til varanlegri geymslu, með skilgreindum 12 mánaða varðveislutíma.

Sýnidæmi um slíkan útflutning er að finna í notendahandbók X-Road öryggisþjóna í kaflanum [Transferring the Archive Files from the Security Server](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md).

### Afrit stillinga öryggisþjóns

Afrit af stillingum X-Road öryggisþjóns er tekið [einu sinni á dag að sjálfgefnu](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) (13.3 Automatic Backups) og þau eru vistuð undir `/var/lib/xroad/backup/` - þaðan sem er vert að flytja þau til varanlegri geymslu, eins og er vikið að fyrir samskiptaskrár í 4.5.3.1. Yfilit afrita er hægt að sjá í umsýsluviðmóti, eins og er lýst í 4.4.2.

Þegar afrit er lesið inn á nýuppsettan þjón í umsýsluviðmóti, þarf að gæta þess að *Server Code* þjónsins sé það sama og afritið inniheldur. Að öðrum kosti er hægt að [lesa inn afritið frá skipanalínu með þvingunarrofum](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) (13.2 Restore from the Command Line).

Sjá nánar í:

* [Back up and Restore](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) kafla notendahandbókar

### Vöktun

X-Road býður upp á umhverfis- og aðgerðavöktun. Aðgerðavöktunin tekur saman upplýsingar um virkni öryggisþjóna, eins og hvaða þjónustur hefur verið kallað í, hve oft, stærð svara, o.s.frv. Gögnum um aðgerðir X-Road öryggisþjóna er safnað saman og þau gerð aðgengileg með viðkomandi skilum (JMXMP) til handa ytri vöktunartólum, eins og Dynatrace, Zabbix, Nagios, Icinga, SolarWinds eða DataDog.

Einnig er hægt að fylgjast með heilsufari öryggisþjóns, hvort hann sé líklegur til að senda og taka á móti skeytum, með því að fylgjast með þar til gerðum HTTP endapunkti. Þessi endapunktur er nýttur í ytri álagsdreifingu til að meta hvort þjónn sé hæfur til að vera virkur þáttakandi í klasa öryggisþjóna.

Nánara lesefni:

* [Operational Monitoring](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) í X-Road notendahandbók
* [Environmental Monitoring](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/ug-ss_x-road_6_security_server_user_guide.md) í notendahandbók X-Road öryggisþjóna
* [X-Road: Operational Monitoring Daemon Architecture](https://github.com/nordic-institute/X-Road/blob/develop/doc/OperationalMonitoring/Architecture/arc-opmond_x-road_operational_monitoring_daemon_architecture_Y-1096-1.md)
* [X-Road: External Load Balancer Installation Guide - Health check service configuration](https://github.com/nordic-institute/X-Road/blob/develop/doc/Manuals/LoadBalancing/ig-xlb_x-road_external_load_balancer_installation_guide.md)


# X-Road Central - current version

## Central Server Version

The current X-Road Central Servers ("Miðjan") are running on [**X-Road v7.0.4**](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/26214406/X-Road+v7.0.4+Release+Notes)

## Recommended Security Server Versions

The following versions of X-Road are currently supported:

* [v7.0.4](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/26214406/X-Road+v7.0.4+Release+Notes)
* [v7.2.x](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/163151873/X-Road+v7.2.2+Release+Notes)
* [v7.1.x](https://nordic-institute.atlassian.net/wiki/spaces/XRDKB/pages/161808385/X-Road+v7.1.3+Release+Notes)


# User profile / Notendaupplýsingar

#### **Introduction**

The User Profile API is now accessible via Straumurinn (X-Road). This service is a REST API that provides access to user profiles on Island.is. A user profile contains the following information

* `nationalId` - Users national id
* `email` - Users email address
* `mobilePhoneNumber`  - Users mobile phone number
* `locale` - Users preferred locale setting, `"en" "is"`
* `mobilePhoneNumberVerified` - Has the user verified their mobile phone number via two-factor authentication
* `emailVerified` - Has the user verified their email address via two-factor authentication
* `documentNotifications` - Boolean indicating if user has document notifications turned on or off
* `emailNotifications` - Boolean indicating if user has email notifications turned on or off
* `profileImageUrl` - Link to the users profile image
* `needsNudge`  - Boolean indicating if the users should be nudged to update their user profile information
* `lastNudge` - Date of when the user was last nudged to update their user profile information
* `nextNudge` - Date of when the user will be nudged next to update their user profile information
* `isRestricted` - The user has not been nudged to update their user profile information since the migration of user profiles to island.is

#### **Access for Government Organisations**

Government organisations can integrate with this service by:

1. Creating a **Machine to Machine Client (Application)** in the **IDS Admin**.
2. Requesting access for this client to the user profile API endpoints via Island.is support.

#### **Available Endpoints**

Once access is granted, organisations can use the following API endpoints:

* **GET** `/v2/users/{national-id}` – Fetch a specific user's profile using their national ID. The query parameter clientType can be ignored.
* **GET** `/v2/users/{to-national-id}/actor-profiles/{from-national-id}` – Retrieve actor profiles.

#### **API Documentation**

The full **OpenAPI Documentation** for this service is available [here](https://island.is/en/o/digital-iceland/webservices/SVNfR09WXzU1MDE2OTI4MjlfaXNsYW5kLWlzX3VzZXItcHJvZmlsZQ).


# Getting Started

This [GitHub organization](https://github.com/island-is) is the center of development for digital government services on `island.is`. It is managed by the [Digital Iceland](https://stafraent.island.is/) department inside the [Ministry of Finance and Economic Affairs](https://www.government.is/ministries/ministry-of-finance-and-economic-affairs/).

These solutions are [FOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) and open to contributions, but most development will be performed by teams that win tenders to develop new functionality for Digital Iceland.

The repository is a [monorepo](/technical-overview/monorepo) that has multiple apps (something that can be built and run) and libraries (which other apps and libraries can depend on). All custom-written services are also stored there.

## GitBook

The apps and libraries documentation and our handbook are hosted on [GitBook](https://www.gitbook.com) and is publicly available at [docs.devland.is](https://docs.devland.is).

## Storybook

The Ísland.is design system is developed and showcased using [Storybook](https://storybook.js.org) and is publicly available at [ui.devland.is](https://ui.devland.is).

## Reading material

To get more technical information about the project please make sure to read this [overview](/technical-overview/technical-overview).

## External contributors

If you want to contribute to the repository, please make sure to follow [this guide](/development/external-contribute).

## Prerequisites

* You have Node and Yarn installed as outlined in the `engines` section in the repository's [`package.json`](https://github.com/island-is/island.is/blob/main/package.json#L5)
* You have [Docker](https://docs.docker.com/desktop/) installed.
* You have [direnv](https://direnv.net/) installed.
* You have [Java](https://www.java.com/en/download/manual.jsp) `>= 1.8` installed (for schema generation).

{% hint style="info" %}
If you are running on Windows we recommend using [Docker and WSL2](https://docs.docker.com/desktop/windows/wsl/)
{% endhint %}

### For fetching secrets

* You have [AWS command line tools v2](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed.
  * `brew install awscli`
* You have [jq](https://stedolan.github.io/jq/) installed.
  * `brew install jq`

## Usage

There are many projects that can be built and run.

To list projects that can be built the following command can be used

```bash
yarn nx show projects --with-target build
```

See further useage of the Nx show command in their [docs](https://nx.dev/nx-api/nx/documents/show).

### Fresh start/changing branches

Run on whenever you check out a branch:

```bash
yarn install
yarn infra
yarn codegen
```

When you clone the repo for the first time, and whenever you change branches, you need to update your dependencies to match your current branch using `yarn install`. In addition, schemas change frequently, so you will also need to update the generated schemas and clients using `yarn codegen`.

### Development server

For a dev server:

```bash
yarn start <project>
```

The app will automatically reload if you change any of the source files.

### Build

To build the project:

```bash
yarn build <project>
```

The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.

### Formatting your code

You need to format all files to follow Nx code conventions. To do so run:

```bash
yarn nx format:write
```

### Running lint checks

We have many lint rules to help having a unify code all over the project. To execute the linting:

```bash
yarn lint <project>
```

> Running lint locally is slow and fill up heap memory. This is related to Typescript compilation and Nx lint builder being slow. As a result you might get a `JavaScript heap out of memory`. Nx is working on fixing this for an upcoming update. In the meantime you can do `NODE_OPTIONS=“--max-old-space-size=4096” yarn lint <project>` to raise the memory limit.

### Running unit tests

To execute the unit tests via [Jest](https://jestjs.io):

```bash
yarn test <project>
```

To execute the unit tests affected by a change:

```bash
yarn affected:test
```

### Running end-to-end tests

See our technical documentation on our [system e2e setup](https://github.com/island-is/island.is/tree/main/apps/system-e2e).

### Schemas

If your project is generating schemas files from an OpenAPI, Codegen or is an API, check out [this documentation](/development/codegen).

### Understand your workspace

To see a diagram of the dependencies of your projects:

```bash
yarn nx dep-graph
```

### AWS Secrets

A dedicated documentation about fetching shared development secrets or creating new secrets, using AWS secrets is available [here](/development/aws-secrets).

### Running proxy against development service

If you have AWS access to our development account, you can connect to development databases and services using a proxy. We've set up a proxy and connection helpers for our development Postgres, Elastic Search, Redis and X-Road Security Server.

To do so, you can run for example:

```bash
./scripts/run-db-proxy.sh
```

It will try to get your AWS credentials from your environment variables and from your `~/.aws/credentials` file. You can find more instructions [here](/development/aws-secrets#using-aws-session).

{% hint style="info" %}
If you want to run your app against one of this service (e.g. `db`), you may need to edit your app environment or sequelize config to pass the proxy credentials.
{% endhint %}

{% hint style="warning" %}
The following services will run on the associated ports: `db:5432`, `es:9200`, `redis:6379`, `xroad:80`. If you have docker running on theses ports or any others services you will need to stop them in order to run the proxies.
{% endhint %}

### Environment variables with static websites

To be able to access environment variables in purely static projects, you need to do the following:

1. In the index.html file, add `<!-- environment placeholder -->`.
2. Use the `getStaticEnv` function from the `@island.is/shared/utils` library to fetch your environment variables.
3. Prefix your environment variables with `SI_PUBLIC_`, for example `SI_PUBLIC_MY_VARIABLE`.

NOTE: This is only to get environment variables when running in kubernetes, not for when running locally. So you should only use `getStaticEnv` in your `environment.prod.ts` file.

What happens behind the scenes is that static projects have a bash script that runs when the docker container starts up. This script searches for references of `SI_PUBLIC_*` in the code and tries to find a match in the environment. It then puts all the matches inside the index.html which is then served to the client.


# Generating a New Project

## Generate a component

To generate a new React component in island-ui-core.

```bash
yarn generate @nx/react:component MyComponent --project=island-ui-core
```

## Generate an application

To generate a simple React application:

```bash
yarn generate @nx/react:app my-app
```

To get a React application with server-side-rendering, we recommend using Next.JS:

```bash
yarn generate @nx/next:app my-app
```

To create a service, you can get started with NestJS like this:

```bash
yarn generate @nx/nest:app services/my-service
```

{% hint style="info" %}
You might want to check out our reference [NextJS](https://github.com/island-is/island.is/tree/main/apps/reference-next-app) and [NestJS](https://github.com/island-is/island.is/tree/main/apps/reference-backend) projects.
{% endhint %}

{% hint style="info" %}
For NextJS projects, be sure to configure our [custom NextJS server](/development/devops/next-server).
{% endhint %}

## Generate a library

To generate a React library.

```bash
yarn generate @nx/react:lib my-lib --linter eslint
```

To create a NestJS module:

```bash
yarn generate @nx/nest:lib my-lib
```

To create a JS library that can be used both on the frontend and the backend:

```bash
yarn generate @nx/node:lib my-lib
```

Libraries are sharable across libraries and applications. They can be imported from `@island.is/my-lib`.

Applications and libraries can be structured in a hierarchy using subfolders:

```bash
yarn generate @nx/node:lib common/my-lib

# Imported from '@island.is/common/my-lib'
```

## Migrations

Using the `sequelize-cli` we support version controlled migrations that keep track of changes to the database.

### Generate a migrations

```bash
yarn nx run <project>:migrate/generate
```

### Migrating

```bash
yarn nx run <project>:migrate
```


# Definition of done

Check-list of acceptance critera when relasing software products to the island.is ecosystem.

**About:** When releasing new features we need to make sure that all acceptance criteria for software products in the [island.is](http://island.is) ecosystem are met before we release on production for the general public. This list should be used as a reference for all projects.

**Responsibility:** The development team and Product Manager from Stafrænt Ísland

**Please make a copy of this page and take out items that are not applicable for your product.**

#### **Accessibility**

* \[ ] **Language support:** All our user-facing products should be available in Icelandic and English.
  * \[ ] No hard-coded strings in the front end
  * \[ ] All strings are available in Contentful with the correct namespace
  * \[ ] Icelandic texts have been reviewed by Stafrænt Ísland
  * \[ ] English texts have been reviewed by Stafrænt Ísland
  * \[ ] If the feature is for organization, the Icelandic text has been reviewed by the org
  * \[ ] If the feature is for organization, the English text has been reviewed by the org
* \[ ] **Accessibility:** UX has support for all. \*\*\*\*More info: [Aðgengismál](https://island.is/en/o/digital-iceland/accessibility)
  * \[ ] Run aXe tests
  * \[ ] Manual test have been run

#### Development and Operational requirements

* \[ ] **Feature flags:** has been created
* \[ ] **Architecture:** has been reviewed by the Core and DevOps team
* \[ ] **Audit log:** all user interactions/changes should be audit logged. <https://docs.devland.is/libs/nest/audit>
* \[ ] **Scopes defined:** If a feature should have the ability to allow others to view, it needs to have scoped defined and documented

  [Scopes](https://docs.devland.is/products/auth/configuration)
* \[ ] **Access for companies, children on behalf**: If working against a web service from an organization, we need to discuss if data can be fetched on behalf of a company, child, disabled, and delegation that another person has given you.

  What you need to ask yourself: As a company, should I be able to access the data? As a parent, should I be able to to access the data? As an individual, should I be able to give this scope to another person, e.g. my partner As a company, should I be able to give this scope to an individual, e.g. my employee
* \[ ] **Logging implemented:** logging and monitoring is ready for operation in production

  <https://docs.devland.is/technical-overview/devops/logging>
* \[ ] **Analytics Usage logged:** we need to be able to monitor the usage of our system. Has analytics been set up in Plausible.

#### Quality Assurance

* \[ ] **Testing.** More info: [**Prófanir**](https://www.notion.so/Pr-fanir-1c947433f6354162ae349b0bc9d91bab?pvs=21)
  * \[ ] Test cases have been reviewed by Product Owner
  * \[ ] External integration test has been created when we depend on third party API´s
  * \[ ] Internal API test has been created
  * \[ ] End to end test has been created

#### Documentation

* \[ ] **Technical documentation:** has technical documentation been added on gitbooks \*\*\*\*
  * \[ ] Has ReadMe file been added to the project in our source control? It should answer what the system does and how to get it up and running. See an example here: <https://github.com/island-is/island.is/blob/main/apps/air-discount-scheme/README.md>
* \[ ] **Article** on [island.is](http://island.is) has been created along with a process entry and the service owner designated in contentful. This is important steps so the user can discover the new product.

#### Stakeholder management

* \[ ] If the feature is done in collaboration with an organization, they have given a green light for the release
* \[ ] If working against a web service from organization, the X-road service must be connected to production and openId connect installed on the service

#### Release

* \[ ] **Test on dev:** Make sure the feature is working 100% in a feature deployment and/or in the dev environment.
* \[ ] **Environment variables:** if the feature uses new environment variables and/or secrets, make sure they are defined and configured correctly in all environments.\
  [Creating secrets](/development/aws-secrets#usage-to-create-secrets)
* \[ ] **Prepare infra:** Is your feature is a new application or if it requires new infrastructure? Verify that your application is listed for deployment in production, your `infra` configuration is correct, and all your resources have been created (eg databases and other AWS resources).
* \[ ] **Client and Scopes**: Is your feature a new application requiring IAS authentication, or does it contain a integration using a new IAS scope? Make sure the IAS is correctly configured in all environments, including client permission configuration and redirect urls.

#### Applications

* \[ ] **Application flow**
  * \[ ] Application state is correctly synced with application overview (UI, application system)
* \[ ] **Compliance**:
  * \[ ] Data collection screen has been approved by org and Stafrænt Ísland. (Application system)
  * \[ ] Usage of roles and access to external data (Application system)
  * \[ ] Application lifetime has been approved by the org and is in sync with MÁP (Application system)
* \[ ] **Payments:** If using ARK-Quickpay, we need to sync with FJS on making the product ID available in QuickPay and synchronize and test the application flow with the callback service to confirm payment.
* \[ ] **Article** on [island.is](http://island.is) has been created along with a process entry and service owner designated in contentful.
  * \[ ] Process entry type is “Application system”

#### After release

* \[ ] **Feature flagging:** When the feature has been deployed to general public, we need to a) clean up the feature flag in code, b) remove the feature flag from config cat. This is an important step!

  <https://docs.devland.is/technical-overview/feature-flags>'
* \[ ] **Tagging articles that contain an application link**: When an article that points to a new digital application has been published in Contentful, it should be tagged with the tag ‘umsokn’. This enables front ends, e.g. the [Ísland.is](https://docs.devland.is/development/http:/xn--sland-hna.is) app, to list it with other fully digital applications.


# Devops

The home for all the infrastructure information you need to know regarding `island.is` services.

## Content

* [Continuous Delivery](/development/devops/continuous-delivery)
* [Dockerizing](/development/devops/dockerizing)
* [Environment setup](/development/devops/environment-setup)
* [Logging](/development/devops/logging)
* [Metrics](/development/devops/metrics)
* [Database](/development/devops/database)
* [Observability](/development/devops/observability)
* [Services setup](/development/devops/service-setup)
* [Operations base principles](/development/devops/operations-base-principles)


# Continuous Delivery

## What is Continuous Delivery(CD)

The first paragraph from [continuousdelivery.com](https://continuousdelivery.com/#main)

{% hint style="info" %}
Continuous Delivery is the ability to get changes of all types—including new features, configuration changes, bug fixes and experiments—into production, or into the hands of users, *safely* and *quickly* in a *sustainable* way.
{% endhint %}

## Why do CD

Top three reasons:

* Lower risk of changes - By delivering smaller changes to production and exercising the deployment process many times a day, we significantly lower the risk of quality regression or unexpected deployment hurdles.
* Faster time-to-market - We often have emergency applications that need to get deployed in production under quite tight deadlines. Having a safe delivery pipeline makes this possible.
* Higher quality - by running our ever-growing regression test suites after every change in the code, we make sure we do not take a step backwards quality-wise.

## Process overview

![cd-overview](/files/-ML85RaV7hpsZCSmAsi7)

## Continuous Integration(CI)

CI is an integral part of the CD. It ensures the quality of the code and packages the assets, making them ready for deployment.

We trigger the CI process for all GitHub Pull Requests targeting the `main` branch without publishing assets. We trigger the CI process and publish the assets when making changes to `main` and `release/**` branches.

We lint the code, check the formatting of the code, perform Node modules vulnerability scan, run the unit and integration tests, run the end-to-end tests (results recorded to cypress.io: <https://dashboard.cypress.io/projects/4q7jz8/>) and finally, if successful, we package the code and assets. You can find a sample script to run the process for an app of your choosing [here](https://github.com/island-is/island.is/blob/main/scripts/ci/README.md). To find out more about the thinking around the CI process, please see the [ADR](/technical-overview/adr/0002-continuous-integration).

Code and assets from [island.is](https://github.com/island-is/island.is) are packaged in Docker containers and stored in a private Docker registry hosted in AWS [ECR](https://aws.amazon.com/ecr/). The [ECR](https://aws.amazon.com/ecr/) is configured to perform [vulnerability scanning](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html) of all Docker images pushed to it.

When the CI process finishes successfully and has published assets, we trigger the Delivery pipeline to the Dev environment.

## Merge queues

Github merge queues apply first-come-first-served policy to all PRs. To merge code to `main`, developers can use githubs "merge when ready" feature which sends PR's to the merge queue once all requirements have been met. Developers do not have privileges to merge/push manually to the main branch to prevent accidents from happening and maintain fairness, since merging manually to main would bypass the merge queue.

## Configuration

Our deployment platform is Kubernetes and our applications' deployment and configuration is specified using [Helm](https://helm.sh). Additionally, we have the configuration for our infrastructure in AWS specified using [Terraform](https://www.terraform.io). These two configuration sources are hosted in two separate git repositories with restricted access.

## Delivery pipeline

The CI process triggers the pipelines upon a successful build, which automatically deploys to our `Dev` environment. After manual approval, it is possible to deploy to `Staging` and then `Prod` as well, via hotfix commit to the release branch.

We use [ArgoCD](https://argo-cd.readthedocs.io/en/stable/) as a deployment tool for Kubernetes. It minimizes manual labor required for deployments by automating which tags are synced (deployed) to our kubernetes clusters across all environments.

Developers are able to see the status of their deployments, logs from the pods including errors that are related to the applications, deployment templates (helm charts) or infrastructure in a simple web&#x20;

[ArgoCD Web interface](https://argocd.shared.devland.is/applications?showFavorites=false\&proj=staging\&sync=\&autoSync=\&health=\&namespace=\&cluster=\&labels=)

ArgoCD organizes the deployments we use into Applications. There we can see information on all kubernetes objects that ArgoCD manages such as the health of the objects, sync status, helm values used, the URL used by the ingress for the app and a link to the configuration repositories.

Application level logs can also be viewed from there by clicking on the deployment and navigating to the logs tab&#x20;

ArgoCD is a GitOps tool in which it continuously watches a [configuration repository](https://github.com/island-is/helm-values) and syncs the status of the configuration to a number of kubernetes clusters.

In our setup, we build our docker images in the merge queue before PRs are merged to either the release branch or the main branch. Then after the merge another job pushes files to the configuration repo which triggers ArgoCD to sync the new changes to our clusters.

We automatically sync feature deployments, dev deployments and staging deployments without any user interactions. Production deployments still require manual sync actions at this point in time.


# Database

We use Sequelize as an ORM for our database.

## Setup

To set up Sequelize in your backend service take a look at [reference-backend](https://github.com/island-is/island.is/tree/main/apps/reference-backend).

## Read replicas

You can enable an application to use read replicas to reduce the load of the database. A read replica is an exact matching replica of your current database that is kept in sync with the original one. This replica is read only and thus called a read replica while the original database allows writes and is called a writer. There can only be one writer but there can be many read replicas.

We can configure Sequelize to use read replicas, it handles the logic of sending all the read commands to the read replicas instead of the writer.

All we need to do is add the connection config for the readers. AWS provides us with a single host name for all of the read replicas. AWS directs the connecting server to an available read replica.

Edit your `sequelize.config.js` and setup the replication object like this:

```javascript
{
  production: {
    replication: {
      read: [
        {
          host: process.env.DB_REPLICAS_HOST,
          username: process.env.DB_USER,
          password: process.env.DB_PASS,
          database: process.env.DB_NAME,
        },
      ],
      write: {
        host: process.env.DB_HOST,
        username: process.env.DB_USER,
        password: process.env.DB_PASS,
        database: process.env.DB_NAME,
      },
    },
  }
}
```

By default Sequelize creates a connection with each of the hosts in the config file and keeps the connection alive as long as possible. That's usually fine but because of autoscaling this usually results in a very uneven distribution of connections between the readers.

To handle that we can recycle the connections periodically. Change `sequelizeConfig.service.ts` and pass in the `recycleConnections` property like this:

```javascript
  getOptions({ recycleConnections: true }),
```


# Dockerizing

## General

The services that you are building need to be packaged as Docker container images. For that, you do not need to write a `Dockerfile` or anything like that. We already have pre-defined types of Docker image packaging that you should use.

## What should I do then?

You need to ask the [DevOps](https://github.com/island-is/island.is/blob/main/handbook/technical-overview/devops/technical-overview/devops/personas.md#devops) team to create a Docker repository for you, which has the same name your service has in NX. This is an important convention to make everyone's lives easier. Then you need to manually add to your project's `project.json` file a target that describes what kind of Docker packaging it needs. For example, adding this target

```json
  "docker-next": {}
```

means your service will be packaged as a NextJS Docker container image. We have support the following types of Docker containers:

* `docker-next`: suitable for [NextJS](https://nextjs.org/) services.
* `docker-express`, suitable for [ExpressJS](https://expressjs.com) as well as [NestJS](https://nestjs.com) services.
* `docker-static`, suitable for serving all types of static content. Suitable for pure HTML or React SPAs.
* `docker-cypress`, suitable for running cypress tests in docker.
* `docker-native`, not implemented

If you would like to see some examples, simply search for "docker" in that file and you should find plenty.

When you push this change to `main` your Docker image will get built and pushed to our private central Docker registry

{% hint style="info" %}
To dockerize a NextJS project, you additionally need to configure it to use [our custom server](/development/devops/next-server#setup-in-new-project).
{% endhint %}

## Can I create a secret in the aws parameters store for services to consume?

Yes you can! Find out about it on the [AWS Secrets documentation](/development/aws-secrets).

## Troubleshooting

*Prerequisite*: Local Docker support

If you are having problems with your application running inside a Docker container, you can troubleshoot that by downloading the Docker container and running it locally on your workstation.

To do that you need to follow this process:

1. Login to our **AWS Shared account** and get command line access settings

   ![Login](/files/-ML85TCVtQMq9O7UkBh1) ![Env copy](/files/-ML85TCYK2gA2YQjdt6O)
2. Open your terminal and paste the AWS creds from the clipboard
3. Run this to authenticate to our private Docker registry

   ```
    aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 821090935708.dkr.ecr.eu-west-1.amazonaws.com
   ```
4. Now you can poke around in the Docker container like this (Docker image and tag can be retrieved from a few places, depending on where you are starting from - Spinnaker, GitHub CI, Kubenav/Kubernetes)

   ```
    docker run --rm -it --entrypoint=sh 821090935708.dkr.ecr.eu-west-1.amazonaws.com/<image>:<tag>
   ```


# Environment Setup

1. Data center
2. Kubernetes
3. Databases
4. Queues
5. Applications

## Data center

### General info

We are currently running our operation in AWS exclusively. We utilize the [fully managed Kubernetes service](https://aws.amazon.com/eks/) as well as other database and messaging services that AWS provides.

We use the `eu-west-1` region (Ireland) for two reasons

* EU regulations regarding data co-location
* Network latency to Iceland

We provision all AWS resources in three Availability Zones so that failure in one of them does not impact our operations. This is also true for the Kubernetes cluster as well.

### Structure

![Typical request handling](/files/-MST0w7PocoU8rJQqiGX)

This structure is based on the guidance coming from a service that helps us plan and control the AWS cloud structure - [AWS Control Tower](https://aws.amazon.com/controltower/).

{% hint style="info" %}
If you’re an organization with multiple AWS accounts and teams, cloud setup and governance can be complex and time-consuming, slowing down the very innovation you’re trying to speed up. AWS Control Tower provides the easiest way to set up and govern a new, secure, multi-account AWS environment based on best practices established through AWS’ experience working with thousands of enterprises as they move to the cloud.

>

{% endhint %}

A few notes about the diagram:

* Dedicated log account where all logs from all AWS accounts are streamed to. This is *append-only* log so no one has the authority to change what has happened
* Shared services account - here we run the infrastructure that is common or needs access to the user-facing accounts(Production/Test/Dev/etc.).
* Transit account - used to control routing of network traffic between the different AWS accounts. Additionally we can add routing to VPN connections. VPN connections might come in handy if we need to connect our cloud setup with on-premise data centers.
* Security account - used for forensics and auditing.
* Production/Test/Dev/etc. accounts - used for deploying our applications. These are what we call our "environments" - "Dev environment", "Prod environment", etc. Here we provision the bulk of our workloads - Kubernetes, databases, queues, etc. Those are not shared between accounts.

## Kubernetes

We use [Kubernetes](https://kubernetes.io) to schedule and run containerized applications. It is the main pillar in our operations and as such it conforms to all of [our base principles](/development/devops/operations-base-principles).

![Typical request handling](/files/-ML85SxfezUYUJ2UIPj8)

A few notes here:

* Networking
  * public subnet - an Internet-facing network. There is very little that we provision here since this is a harsh place to be. Notably Load balancers and NAT Gateways are provisioned here.
  * private subnet - only accessible from the public subnet. This is where we run our Kubernetes cluster. Workloads running here have outbound access to the Internet by means of a NAT Gateway.
  * database subnet - only accessible from the private subnet. No Internet access in or out.
* Security
  * AWS WAF
    * protection against [common web-based attacks](https://owasp.org/www-project-top-ten/)
    * IP-based filtering
  * Security groups - each Kubernetes pod can be granted identity and permission set to access only the AWS resources it needs

## Databases

We use fully managed AWS database services. Although AWS offers a wide variety of databases we limit ourselves to a small subset of those where we have deeper expertise in managing and troubleshooting.

We use the following databases as of this writing:

| AWS service name  | OSS equivalent | Purpose                     | Application applicability  |
| ----------------- | -------------- | --------------------------- | -------------------------- |
| AWS Aurora        | Postgres       | Relational DB               | `critical`, `non-critical` |
| AWS ElastiCache   | Redis          | In-memory cache and pub/sub | `critical`, `non-critical` |
| AWS Elasticsearch | ElasticSearch  | Document searching          | `critical`, `non-critical` |

## Queues

We use [AWS SQS](https://aws.amazon.com/sqs/), which is a fully managed queue service. This is a proprietary service and protocol so it is not suitable for `critical` applications.

## Applications

We use the term `application` only for service stacks that we deploy to our Kubernetes cluster. These could be in-house developed applications or off-the-shelf ones. Each application needs to be classified in each of these dimensions:

* importance
  * `critical` - this application provides an essential service. Its design decisions must be reviewed by the DevOps team at the inception of the application. It cannot use proprietary tech.
  * `non-critical` - optional service that might take some time to bring on-line in case of a disaster or moving to on-premise
* SLA
  * `personal` - services for individuals. 9-5 and [MTTR](https://en.wikipedia.org/wiki/Mean_time_to_recovery)(mean time to recovery) 5 hours?
  * `business` - services for businesses. 9-5 and MTTR 2 hours?
  * `24/7` - critical service. 24/7 and MTTR 1 hour?


# Logging

Logging is one of the foundational pieces of telemetry we need to understand issues at runtime. It is therefore deemed one of the core responsibilities of developers to provide meaningful logs.

## Logging infrastructure

Developers should use the `logging` library that is part of the monorepo and is configured for local as well as production environments. Don't use other methods of logging since that could lead to log statements not getting delivered correctly to the central log store.

## Logging levels

The logging levels to be used are `error`, `warn`,`info` and `debug`. Everything from level `info` and up (that's `info`, `error` and `warn`) are delivered to the central log store. You can use all the levels of course but the logs with logging level lower than `info` will be discarded when deployed to one of the environments. We can change the logging level for a specific service to a lower level but that is a manual operation, to be used only as a last resort.

Example - [logging](https://github.com/island-is/island.is/blob/main/apps/reference-backend/src/app/modules/resource/resource.service.ts#L31-L33)

## Viewing logs

You can search for and view the logs from all environments at [https://app.datadoghq.eu/logs](https://app.datadoghq.eu/logs?env=dev).

## Best practices

Use `error` when you are reporting errors or exceptions.

Use `warn` when things are in 'suspicious' or potentially problematic state.

Use `info` when reaching important states - server started, user created, registration complete, etc. or anything worth knowing about

Use `debug` for additional info.

Avoid logging at level `info` inside unbounded loops.

Don't log the same exception/error multiple times.

Do not log full personal identifiable or other sensitive information. User database IDs are preferred to users' names for example.


# Metrics

Metric is one of the foundational pieces of telemetry we need to understand issues at runtime. It is theresfore deemed one of the core responsibilities of developers to provide metrics in their services.

## Metrics infrastructure

~~We are using~~ [~~Prometheus~~](https://prometheus.io) ~~for collecting, storing and querying metrics. To see the different metric types available please see~~ [~~here~~](https://prometheus.io/docs/concepts/metric_types/)~~. For more information on the naming of metrics, please see~~ [~~here~~](https://prometheus.io/docs/practices/naming/)~~.~~

~~If you are using the `infra-express-server` or `infra-next-server` libraries you already have the metrics infrastructure setup for you. Additionally, we already provide metrics for the routes you are creating.~~

## Types of metrics

We are collecting metrics at three distinct levels:

* infrastructure
* runtime
* application

**Infrastructure** metrics are gathered from different layers of infrastructure - cloud, operating system, Kubernetes, Docker.

**Runtime** metrics are gathered from our application runtime - NodeJS. These are about the utilization of different types of heap, CPU, etc.

**Application** metrics are about the entities and operations performed on those, that are in the domain of the application. Providing these metrics is a responsibility of the developers. It is important to have metrics for both successful as well as unsuccessful operations. For example: "application registration successful", application registration failed", etc. For an example, please take a look at this [file](https://github.com/island-is/island.is/blob/main/libs/infra-express-server/src/lib/infra-express-server.ts).


# NextJS Custom Server

We use a custom NextJS server to standardise logging, tracing and metrics in production. This uses NX's official support for [custom servers in NextJS](https://nx.dev/packages/next/generators/custom-server).

## Setup in new project

Follow these steps to configure our custom NextJS server in your NextJS project:

1. Add a `server.ts` file to the root folder of your NextJS project with the following content. Be sure to replace the `{{variables}}` with correct values. See `apps/web/server.ts` for example setup.

```typescript
import { bootstrap } from '@island.is/infra-next-server'

bootstrap({
  name: '{{projectName}}',
  appDir: 'apps/{{pathToAppDir}}',
})
```

2. Then create a new tsconfig file called `tsconfig.server.json` with the following contents. Be sure to replace the `{{variables}}` with correct values.

```
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "noEmit": false,
    "incremental": true,
    "tsBuildInfoFile": "../../{{extraRelativePathToRoot}}tmp/buildcache/apps/{{pathToAppDir}}/server",
    "types": [
      "node"
    ]
  },
  "include": ["server.ts"]
}
```

3. Finally, open the `project.json` file in your project folder and replace the "build" and "serve" target keys with the following content. Remember to replace the `{{variables}}` with correct values, and edit the `build` configurations as needed.

```json
"build": {
  "executor": "@nx/next:build",
  "outputs": ["{options.outputPath}"],
  "defaultConfiguration": "production",
  "options": {
    "outputPath": "dist/apps/{{pathToAppDir}}"
  },
  "configurations": {
    "development": {
      "outputPath": "apps/{{pathToAppDir}}"
    },
    "production": {}
  },
  "dependsOn": [
    "build-custom-server"
  ]
},
"build-custom-server": {
  "executor": "@nx/webpack:webpack",
  "defaultConfiguration": "production",
  "options": {
    "outputPath": "dist/apps/{{pathToAppDir}}",
    "main": "apps/{{pathToAppDir}}/server.ts",
    "tsConfig": "apps/{{pathToAppDir}}/tsconfig.server.json",
    "maxWorkers": 2,
    "assets": [],
    "compiler": "tsc",
    "target": "node"
  },
  "configurations": {
    "development": {},
    "production": {
      "optimization": true,
      "extractLicenses": true,
      "inspect": false
    }
  }
},
"serve": {
  "executor": "@nx/next:server",
  "defaultConfiguration": "development",
  "options": {
    "buildTarget": "{{projectName}}:build",
    "dev": true,
    "customServerTarget": "{{projectName}}:serve-custom-server"
  },
  "configurations": {
    "development": {
      "buildTarget": "{{projectName}}:build:development",
      "dev": true,
      "customServerTarget": "{{projectName}}:serve-custom-server:development"
    },
    "production": {
      "buildTarget": "{{projectName}}:build:production",
      "dev": false,
      "customServerTarget": "{{projectName}}:serve-custom-server:production"
    }
  }
},
"serve-custom-server": {
  "executor": "@nx/js:node",
  "defaultConfiguration": "development",
  "options": {
    "buildTarget": "{{projectName}}:build-custom-server"
  },
  "configurations": {
    "development": {
      "buildTarget": "{{projectName}}:build-custom-server:development"
    },
    "production": {
      "buildTarget": "{{projectName}}:build-custom-server:production"
    }
  }
},
```


# Observability

## Intro

We need to ensure that the applications stay available and performant once they have been deployed to Production. For that to happen we need all of these things to happen:

* Provide observability into the applications
* Define the boundaries of expected behaviour
* Document applications' components and their maintenance operations
* Application recent change history
* Contact information for dev team emergency contact

### What is observability

Here is a [sample chapter from the book Distributed Systems Observability by Cindy Sridharan](https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/ch04.html) that talks about the three pillars of observability - logs, metrics and traces. We are starting with these basics and we are planning to add more - stack-trace collecting, deployment events, etc.

### Provide observability into the applications

![Monitoring at SÍ](/files/-ML85SpgJUT2FRU26hmc)

#### Logs

There is a clear separation of strategy where we keep the logs:

* all AWS services send their logs to AWS CloudWatch
* all services running in Kubernetes send their logs to DataDog

There are a few reasons we keep the AWS services logs in CloudWatch - price, native integration, target audience (ops), etc. For developers is enough to have access to DataDog, since those logs are most relevant to their apps and services.

#### Metrics

For metrics we use DataDog. We collect metrics from both AWS services as well as our custom built Kubernets services. These metrics are useful for observability - runtime behaviour over longer periods of time, as well as for alerting about abnormal behaviour.

#### Tracing

We use DataDog for effortless Application Performance Monitoring (APM). With this capability, we get end-to-end visibility into our services - from the web browser, all the way to the database. In the context of a microservice architecture, this is an essential tool to undertand behaviour during interactions and troubleshoot individual issues.

![DataDog APM](/files/-MST0wX1juEQ6QrQQ_iQ)

#### Accessing logs, metrics and traces

Every developer has access to logs, metrics and tracing (APM) information through the [DataDog portal](https://app.datadoghq.com).

### Define the boundaries of expected behaviour

When it comes to metrics we need to baseline the correct behaviour. That usually takes a few days, maybe even weeks. Together, the Ops and Dev team can decide the allowed deviation from the baseline behaviour.

### Document applications' components and their maintenance operations

[Ops](https://github.com/island-is/island.is/blob/main/handbook/technical-overview/devops/technical-overview/devops/personas.md#ops) need to know each application's components, how they interact together as well as interaction with any external services. For example the following information would be really useful:

* component type - web service, web frontend, message processor, etc.
* description - the purpose and responsibilities of this component.
* authentication - the auth model for the service - `user-token`, `service-token`, `none`, etc
* dependencies
  * local
  * external
* operations (routes/paths/etc) - the different entry points into this component. For each operation:
  * description - a short description of the operation
  * path - path, topic, etc. that identify the operation
  * parameters - a list of the parameters
    * name - string
    * type - string
    * required - boolean
  * type - `query`, `modify` or `query-modify` behaviour
  * verb - HTTP verb if applicable
  * examples - could be really helpful to have a few `curl` examples

### Application recent change history

Ops need to have access to the recent history of significant changes for each application. That can provide important clues, helpful for the resolution of an issue.

### Contact information for dev team emergency contact

In case Ops cannot resolve the issue in a timely manner with the available tools and information, they will seek for assistance from the development team that has worked on the application experiencing the issue. The process of handling an issue is described in Handling production issues (TODO missing document)


# Operations Base Principles

Here are the principles that we apply when deciding how to run Operational workloads. They come from the management team at Stafrænt Ísland.

1. Secure access to data and services
2. Minimize downtime
3. Allow for Developers to move fast
4. Be prepared for running a subset of critical services on-premise
5. Minimize operational overhead
6. Minimize expenses

## Security

We utilize all our expertise when provisioning infrastructure to apply state-of-the-art security in the cloud. We do our part to fulfill our responsibility in the [Shared Responsibility Model](https://aws.amazon.com/compliance/shared-responsibility-model/).

## Minimize downtime

We strive to apply changes to our Production environment that we are certain of the impact. That requires us to have pre-Production environment that is very close to the Production one where we exercise all changes before they are applied to Production. We also monitor our Production environment according to the Service-Level Agreements(SLA) for the individual services running there.

## Allow for Developers to move fast

We need to allow the Organization be able to deliver new services to the users and iterate on those quickly and safely. The same goes for fixes and improvements. That's why our Org has invested heavily in infrastructure as well as engineering practices and processes that allow the teams to create new applications with minimal operational overhead. This is achieved by standardizing and pre-packaging all infrastructure concerns in libraries and automation while keeping up with security standards.

## Be prepared for running a subset of critical services on-premise

As part of Iceland's government infrastructure, we need to be prepared to run a subset of our services in a local data center. To achieve that, we need to use technologies that are known to work on-premises. Fortunately, the majority of the core tech today is open-source or is based on open standards, which makes this requirement quite achievable. Non-critical services can utilize all the advantages of the cloud.

## Minimize operational overhead

We are using fully managed services in the cloud as much as possible since the TCO is much lower then managing them ourselves. We try to focus our operational effort on the unique services our Organization develops.

## Minimize expenses

We utilize our cloud expertise to minimize the cost of running in the cloud.


# Security

## Access to GitHub and deployment environments

All GitHub accounts with access to `island-is` need to have two-factor authentication (2FA) enabled. This is enforced at the organization level.

### Gaining write access to the codebase and AWS

To join one of the teams at the GitHub organization `island-is`, one of the Delivery Managers needs to request that in the Slack channel #organizational-access-changes. After approval from a representative of Stafrænt Ísland, the GitHub account will be added.

### Team members leaving

When a team member is no longer working for Stafrænt Ísland, the Delivery Manager whose team the member belonged to, needs to announce that on Slack channel #organizational-access-changes. DevOps team will revoke the team member's account access to the GitHub org and AWS accounts.

### Periodic review of team members

Every month DevOps team will remind the Delivery Managers to review the list of team members that have access to GitHub. In case Delivery Managers discover team members that are no longer working for Stafrænt Ísland, they need to notify DevOps team on Slack channel #organizational-access-changes.


# Service Configuration

## Deploying our services

The services we are developing are deployed to Kubernetes using Helm. We have developed a mini DSL in TypeScript to help us with the configuration of the services as well as allow us some flexibility when creating feature deployments compared to the static YAML. The configuration for each service is part of the source code for the service, in a separate folder named `infra`.

The DSL is helping us enforce certain conventions and responsibilities. For example it helps us make sure that secrets values are present in all environments that we are deploying to. Same for environment variables' values.

## Server-side feature flags

We already have a method to roll out [feature flags](/development/feature-flags) to users, so you might be wondering what are these "server-side" features all about. These are features that are not specific to users or groups of users. They are intended for features that are not ready for production (or staging) yet usually due to:

* lack of configuration information
* incomplete implementation

Using these features you can deploy the code all the way to production without having to provide secret or environment variables values for the env where the feature is not turned on.

Currently the feature-specific configuration that can be specified is environment variables and secrets. For an example please see [this file](https://github.com/island-is/island.is/blob/main/infra/src/dsl/toggles.spec.ts).

Here is an example of how to use these:

```
  const sut = service('api')
    .namespace('test')
    .image('test')
    .env({
      B: 'A',
    })
    .features({
      'integration-A': {
        env: {
          A: {
            dev: 'B1',
            staging: 'B',
            prod: MissingSetting, // this allows us to specify that we still do not know that the value is
          },
        },
        secrets: { KEY: '/k8s/secret' },
      },
    })
    .initContainer({
      containers: [{ command: 'go' }],
      features: {
        'integration-A': {
          env: {
            C: 'D',
          },
          secrets: {
            INIT: '/a/b/c',
          },
        },
      },
    })
```

### Turning the features on and off

The features are turned off by default and need to be turned on explicitly in the [environment configuration](https://github.com/island-is/island.is/blob/main/infra/src/environments.ts) using the field `featuresOn`.

### Using the features in the code

The only usage of the features is to check whether a flag is "on". To do that, use the `ServerSideFeatureClient` object [exported in the feature flags library](https://github.com/island-is/island.is/blob/main/libs/feature-flags/src/lib/server-side-client.ts).

### Cleaning up

After the feature is in use on prod, please remove all references to it in the code.


# Support

## Ops

The team monitoring the operational environment

## DevOps

The team supporting the Dev teams with infrastructure for development, building and deploying our applications. A few useful Slack channels to be aware:

* [DevOps support group](https://islandis.slack.com/archives/C019LNRM6LE)
* [DevOps discipline group](https://islandis.slack.com/archives/C013A6RBD34)

## Devs

The teams developing the applications. Some of them are [DevOps](#devops) too.


# AWS Secrets

## Prerequisites

* You will need [AWS command line](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed.
* You have [jq](https://stedolan.github.io/jq/) installed.
  * `brew install jq`
* You will also need access to the AWS account. Ask someone from DevOps to send you an invitation.

## Getting started

### Using AWS SSO

Using SSO is the most straight forward solution. You won't need to go by yourself on your AWS account and it will open the needed url for you.

* Run the sso command for the first time

{% hint style="warning" %}
In recent aws-cli version it started to ask for *SSO session name.* Currently island.is accounts doesn't support that and depends on configuring it with the legacy format. \
\
So it's important to press `Enter` without specifing any value in the `SSO session name (Recommended):` question
{% endhint %}

```bash
aws configure sso

# Press enter without specifing any value for the first question
SSO session name (Recommended):
WARNING: Configuring using legacy format (e.g. without an SSO session).
Consider re-running "configure sso" command and providing a session name.
SSO start URL [None]: https://island-is.awsapps.com/start
SSO Region [None]: eu-west-1
```

Then choose the environment of your choice. Likely to be `island-is-development01`. You will be prompted for the following:

```md
CLI default client Region [eu-west-1]: <Press Enter>
CLI default output format [json]: <Press Enter>
CLI profile name [AWSPowerUserAccess-X]: <Custom name (e.g. islandis-dev)> or <Press Enter>
```

This step will add the new profile to your `~/.aws/config` file. If you choose `islandis-dev` as profile's name, you will see `[profile islandis-dev]` in there.

* Ready to use

You can now pass your profile to the `get-secrets` script.

```bash
AWS_PROFILE=<profile-name> yarn get-secrets <project-name> # e.g. profile-name -> islandis-dev as seen above
```

{% hint style="info" %}
**Refresh your profile:** The SSO credentials only lasts 8 hours, after which AWS commands start failing. You can run the following command to renew your SSO credentials.

```bash
aws sso login --profile <profile-name> # e.g. profile-name -> islandis-dev as seen above
```

It will open the browser, go to your AWS account to log in and will refresh your credentials and you are ready to use the AWS commands again.
{% endhint %}

{% hint style="info" %}
**Pre-configured AWS profiles:** Feel free to copy and paste these to your `~/.aws/config` file:

```
[profile islandis-dev]
sso_start_url = https://island-is.awsapps.com/start
sso_account_id = 013313053092
sso_role_name = AWSPowerUserAccess
sso_region = eu-west-1
region = eu-west-1

[profile islandis-staging]
sso_start_url = https://island-is.awsapps.com/start
sso_account_id = 261174024191
sso_role_name = Secret_Service
sso_region = eu-west-1
region = eu-west-1

[profile islandis-prod]
sso_start_url = https://island-is.awsapps.com/start
sso_account_id = 251502586493
sso_role_name = Secret_Service
sso_region = eu-west-1
region = eu-west-1
```

{% endhint %}

{% hint style="info" %}
**AWS Vault:** You can use [AWS Vault](https://github.com/99designs/aws-vault) to store and access AWS credentials in your operating system's secure keystore. When requesting credentials from an expired SSO session, it will automatically open a browser window for you to log in again.

Just follow its [installation instructions](https://github.com/99designs/aws-vault#installing) and configure your `~/.aws/credentials` file like this:

```
[islandis-dev]
credential_process = aws-vault exec islandis-dev --json

# ... do the same thing for your other profiles.
```

{% endhint %}

### Using AWS session

This method is more manual where you will need to export environments variables or change a file by yourself.

You will need to go to your [AWS account](https://island-is.awsapps.com/start) and get the required credentials for the account you need.

* Option 1: Set environment variables

You can copy/paste these environment variables to your terminal:

```bash
export AWS_ACCESS_KEY_ID=AWS_ACCESS_KEY_ID_EXAMPLE
export AWS_SECRET_ACCESS_KEY=AWS_SECRET_ACCESS_KEY_EXAMPLE
export AWS_SESSION_TOKEN=AWS_SESSION_TOKEN_EXAMPLE
```

* Option 2: Edit `~/.aws/credentials`

Copy/paste the values in the `~/.aws/credentials` file.

```bash
[default]
aws_access_key_id = <KEY_ID>
aws_secret_access_key = <ACCESS_KEY>
aws_session_token = <SESSION_TOKEN>
```

* Ready to use

In this case you won't need to pass a profile name as opposed to the SSO method.

```bash
yarn get-secrets <project-name>
```

{% hint style="info" %}
**Refresh your profile:** The session token only lasts 1 hour, after which AWS commands start failing. You will need to log in to your AWS account and get new credentials, with one of the above methods.
{% endhint %}

## Usage to fetch secrets

You should now be able to fetch secrets for the project you need.

**With SSO**

```bash
AWS_PROFILE=<profile-name> yarn get-secrets <project> [options]
```

**Without SSO**

```bash
yarn get-secrets <project> [options]
```

**Example**:

```bash
yarn get-secrets api
```

You can verify it by opening the `.env.secret` file at the root, or inside your code using for example:

```typescript
const { MY_SECRET_KEY } = process.env
```

You can also add the `--reset` argument to the command, that will reset the .env.secret file.

### Troubleshoot

If you get the following error message, you will need to refresh your credentials as explained above.

```bash
An error occurred (ExpiredTokenException) when calling the GetParametersByPath operation: The security token included in the request is expired
```

## Usage to create secrets

You can run the following command and will be prompted for input.

**With SSO**

```bash
AWS_PROFILE=<profile-name> create-secret
```

**Without SSO**

```bash
yarn create-secret
```

{% hint style="warning" %}
Only alphanumeric characters, `/` and `-` are allowed. The length of the *secret name* should be from 6-128 characters long.
{% endhint %}

You will be asked for a *secret name* that will be added to the `/k8s/` secrets namespace, a *secret value* and the *secret type* (`SecureString` or `String`).

### Example

```bash
➜ yarn create-secret

Secret name: /k8s/my-app/MY_APP_KEY
# Name: Ok!
# Length: Ok!

Secret value: a-very-secure-secret
# Length: Ok!

SecureString [Y/n]? # [enter] for SecureString
# SecureString selected

Add tags? [y/N]? # [enter] to skip creating tags

Example: Key=Foo,Value=Bar Key=Another,Value=Tag: # note: Key and Value are case sensitive! Create multiple tags by separating with whitespace.

Are you sure [Y/n]? # [enter] to confirm
# Creating secret....
```

{% hint style="info" %}
It's recommended to use `SecureString` in most cases. However, if you need to add an email address, or an email sender's name to the secrets, you can just use a `String`.
{% endhint %}

{% hint style="info" %}
Note that this command only creates the secret in one AWS account at a time (eg `island-is-development01`). To create a secret in all environments, you need to run it with each corresponding AWS account configured, by going through the steps in [Using AWS session](#using-aws-session) multiple times.

To make this easier we recommend configuring SSO for each AWS account using a different AWS profile (islandis-dev, islandis-staging, islandis-prod). Then you can create a secret in all environments like this:

```bash
# If your SSO session is expired and you're not using AWS Vault, you can log into any one profile since they all share the same SSO session.
AWS_PROFILE=islandis-dev aws sso login

AWS_PROFILE=islandis-dev yarn create-secret
AWS_PROFILE=islandis-staging yarn create-secret
AWS_PROFILE=islandis-prod yarn create-secret
```

{% endhint %}

### Finalizing creating secrets

In order to use the secrets in your app you need to add it to its `infra` configuration.

1. Add the new secret to `your-app/infra/your-app.ts`
2. Generate helm charts for your app with

```
yarn charts islandis
```

3. Follow the documentation on [Config Module](broken://pages/14Dr9K25pSsTesi0rIvc)

## Making dev secrets available locally

Environment variables that should not be tracked but needed locally should be added to the `.env.secret` file. *(**NOTE:** Each variable must be prefixed with `export` for direnv to pick them up.)*

Additionally, you can fetch secrets configured in a project's infra DSL from the `island-is-development01` AWS Parameter Store. Just run `yarn get-secrets <project>` and they'll be loaded into your `.env.secret` file.

## Environment variables with static websites

More about it on the root [README](/development/getting-started#environment-variables-with-static-websites).

## Running proxy against development service

More about it on the root [README](/development/getting-started#running-proxy-against-development-service)


# Feature Flags

## Developer usage

If you want to introduce something behind a feature flag you can follow these steps:

1. Ask someone from DevOps for invite to ConfigCat.
2. Once you're in (<https://app.configcat.com/>) you can add your feature flag. The initial values should always be "On" in Dev and (probably always to start with) "Off" in Production and Staging.
3. Make sure that the CONFIGCAT\_SDK\_KEY environment variable is `export`ed in `.env.secret` in the root of the repository. You can fetch it by calling for example `yarn get-secrets service-portal`.
4. Start using your flag by using the package `@island.is/feature-flags`.

## Naming convention

When creating your feature flag, please try to have both the "Key for humans" and "key for programs" descriptive. If the feature flag will be used by a single service, make sure that at least the human key contains the service name. Adding a clear description will also help others knowing what your new flag does.

Example: Your service name is "my-awesome-service" and you're introducing a feature flag called "show-content". The key for humans could be "My awesome service: Show content" and the key for programs could be "myAwesomeServiceShowContent" (Hint: The UI generates the program key automatically from the human key)

## Feature flag lifecycle

After a feature flag has been flipped on for all environments be mindful to clean it up. That involves removing all mentions of that flag in the source code and deleting it from ConfigCat. You will need to contact an administrator to delete the flag.

## Feature flag for applications

You can introduce feature flags to applications. The flag determines whether the applications is accessible for users. See readme [here](https://docs.devland.is/libs/application/core#feature-flags) on further details on how to implement.


# Documentation Contributions

Adding new content to our documentation is very straight forward.

## Contributing

The documentation works in two different ways:

* `Handbook` (hosted on GitBook at [docs.devland.is](https://docs.devland.is)) which contains all the documentation regarding all the island.is projects. You will find technical overview, architectural decisions, API design guide, devops guide, code reviews guide, X-Road guide, code standards detailed information and much more. If you need to edit an existing documentation or create a new page inside the handbook, you simply go to [app.gitbook.com](https://app.gitbook.com) and start writing your content and make a change request.
* `Technical developer guides` which are all the READMEs from the `apps` and `libs` directories in our [GitHub repository](https://github.com/island-is/island.is). If you need to edit or create new content follow our [External Contributions guide](/development/external-contribute) and make the corresponding changes in the GitHub repository. We recommend using [this template](/misc/gitbook-template) when you create a new app in the `apps` directory.

{% hint style="info" %}
If you need access to GitBook head over to the #organizational\_access\_changes channel on Slack.
{% endhint %}


# Defining Monorepo Boundaries With Tags

Tags are a way to define boundaries in a monorepo. They are configured in the `project.json` file of each project, and they affect which projects can depend on each other.

The root `.eslintrc.json` file specifies our rules for each tag. We recommend reading this article [to get up to speed](https://blog.nrwl.io/mastering-the-project-boundaries-in-nx-f095852f5bf4).

## Our tag convention

Our tags are split in 2 categories. Generic tags and application tags.

### Generic tags

Generic tags are based on the frameworks we use and should be used for simple applications and shared libraries.

These are the generic tags ordered from the most generic to more specific.

| Tag          | Description                              | Can depend on                      | Can be depended on by              |
| ------------ | ---------------------------------------- | ---------------------------------- | ---------------------------------- |
| `js`         | Basic JS library.                        | `js`                               | Any project                        |
| `node`       | NodeJS server-side library.              | `js`, `node`                       | Any server-side projects.          |
| `dom`        | JS library designed to run in a browser. | `js`, `dom`                        | Any browser-based project.         |
| `react`      | React library.                           | `js`, `dom`, `react`               | Any react project.                 |
| `nest`       | NestJS library.                          | `js`, `node`, `nest`               | NestJS projects.                   |
| `react-next` | NextJS library.                          | `js`, `dom`, `react`, `react-next` | NextJS projects.                   |
| `react-spa`  | React library using react-router.        | `js`, `dom`, `react`, `react-spa`  | React projects using react-router. |

### Application tags

Simple applications can be tagged with the generic tags above, but applications which have one or more "private" library projects should define their own NX tags, extending one of the generic tags.

It can be one tag which is applied to both the application project and all the associated library projects (like "api"). Or there can be multiple application tags with different rules to segment the library projects (like the "judicial-system" tags).

| Tag                      | Description                     | Can depend on                                                                          | Can be depended on by                 |
| ------------------------ | ------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------- |
| `api`                    | API domain project.             | `js`, `node`, `nest`, `api`, `client`                                                  | Other API projects.                   |
| `application-system`     | Application system projects     | `js`, `dom`, `react`, `react-spa`, `react`, `application-system`, `client`             | Other application system projects     |
| `application-system-web` | Application system web projects | `js`, `dom`, `react`, `react-spa`, `application-system-web`, `application-system`,     | Other application system web projects |
| `application-system-api` | Application system api projects | `js`, `node`, `nest`, `client`, `application-system`, `application-system-api`, `api`, | Other application system api projects |
| `auth-api`               | Authentication api projects     | `js`, `node`, `nest`, `client`, `auth-api`                                             | Other auth APIs                       |
| `client`                 | Client projects.                | `js`, `node`, `nest`, `client`                                                         | Other clients and application-system  |
| `e2e`                    | Test projects                   | `js`, `client`, `application-system`                                                   | No one                                |
| `judicial-system`        | Judicial system projects        | `js`, `judicial-system`                                                                | Other judicial system projects        |
| `judicial-system-api`    | Judicial system web projects    | `js`, `node`, `nest`, `client`, `judicial-system`, `judicial-system-api`               | Other judicial system api projects    |
| `judicial-system-web`    | Judicial system api projects    | `js`, `dom`, `react`, `react-spa`, `judicial-system`, `judicial-system-web`            | Other judicial system web projects    |
| `portals`                | Portal project.                 | `js`, `dom`, `react`, `react-spa`, `portals`                                           | Other portal projects.                |
| `portals-mypages`        | My pages portal project.        | `js`, `dom`, `react`, `react-spa`, `portals`, `portals-mypages`                        | Other my pages portal projects.       |
| `portals-admin`          | Admin portal project.           | `js`, `dom`, `react`, `react-spa`, `portals`, `portals-admin`                          | Other admin portal projects.          |

Here is a chart that displays how these tags are connected. Each tag can depend on other tags with a full line arrow pointing to it. Dotted lines represents connections between application tags where a project can depend on the tag but not necessarily other tags further up.

```mermaid
  flowchart BT;
    %% Generic tags
    node & dom --> js
    react --> dom
    react-spa & react-next --> react
    nest --> node

    %% App tags
    judicial-system --> js
    api & auth-api & client & application-system-api & judicial-system-api --> nest
    application-system & application-system-web & portals & portals-admin & portals-mypages & judicial-system-web --> react-spa

    classDef appTag fill:#f9f
    class api,auth-api,client,application-system,application-system-web,application-system-api,portals-admin,portals-mypages,judicial-system-api,judicial-system-web,judicial-system appTag

    %% Shallow dependencies
    api & auth-api -.-> client
    application-system -.-> client
    application-system-api & application-system-web -.-> application-system
    judicial-system-api & judicial-system-web -.-> judicial-system
    portals-mypages & portals-mypages -.-> portals
```

## Tag prefixes

The above tags **must** be prefixed by one or both of the following prefixes to opt projects into "Can depend on" and "Can be depended on by" rules.

* `scope:` - by applying a scope tag to a project, you are saying that ESLint should enforce project boundaries for that project using the "Can depend on" rules documented above.
* `lib:` - lib tags describe what kind of project it is to enforce the "Can be depended on by" rules documented above.

All projects must have a "scope" tag and most libraries should have the same tag as "lib" and "scope".

Later we hope to get rid of the "lib" tags and just have "scope" tags. However, first we need to fix or refactor a few tricky projects.

### Examples

Generic NextJS application:

```json
{
  "tags": ["scope:react-next"]
}
```

React library which works for both NextJS and React SPA projects.

```json
{
  "tags": ["lib:react", "scope:react"]
}
```

NestJS library.

```json
{
  "tags": ["lib:nest", "scope:nest"]
}
```

## Fixing module boundary errors

> A project tagged with "scope:X" can only depend on libs tagged with "lib:Y", "lib:Z", ... - @nrwl/nx/enforce-module-boundaries

Check which file the code is importing and which tags are configured in the importing project and the imported library.

In some cases, your project should not be importing that library, e.g. it's a library belonging to another application, or you're accidentally importing a server side library from a web project. You should look for ways to refactor your code to not depend on that library. For example, you might move the things you need to another shared library which you are allowed to depend on.

If your project should be able to import that library, then there's some issue with the tags which you need to fix.

Either way, feel free to reach out to the core team and ask for guidance.

> External checks: Missing nx tags for project boundaries

Our CI checks that all projects have correct tags. If you get this error, it's likely that you forgot to add a "scope:" tag to a new `project.json` file. You can re-run the CI check locally by running `yarn check-tags`.


# OpenAPI

Our services are implemented using the NestJS framework which includes SwaggerUI/OpenAPI support. We should always include an OpenAPI document for our public REST services and use the SwaggerUI to make it accessible.

Our `infra-nest-server.bootstrap` accepts a parameter of type `OpenAPIObject` which is used to configure the SwaggerUI. The service should set the base properties in `openApi.ts` and then use [NestJS OpenAPI Decorators](https://docs.nestjs.com/openapi/decorators) on controllers, methods, models and DTOs.

Example of `openApi.ts`

```typescript
import { DocumentBuilder } from '@nestjs/swagger'

export const openApi = new DocumentBuilder()
  .setTitle('IdentityServer Public API')
  .setDescription(
    'Public API for IdentityServer.\n\n\nThe swagger document can be downloaded by appending `-json` to the last path segment.',
  )
  .addServer(process.env.PUBLIC_URL ?? 'http://localhost:3370')
  .setVersion('1.0')
  .build()
```

For more details about OpenAPI support in NestJS read their [docs](https://docs.nestjs.com/openapi/introduction).

## Download the OpenAPI document

The SwaggerUI makes the document itself accessible on the same path with `-json` added. For example if the SwaggerUI is rendered on `https://innskra.island.is/api/swagger` then the document can be downloaded from `https://innskra.island.is/api/swagger-json`.

As the SwaggerUI is missing a download button, we should include a short message in the description field, how the document can be downloaded. This helps our service consumers to get the document for client and model generation.

## Setting server property

In the `openApi.ts` example above, we add the server property. To get the environment specific host details we use the environment variable `PUBLIC_URL`. This variable needs to be set in the service infra dsl (or helm chart if it's not yet part of the monorepo infra namespaces).

## Configuring SwaggerUI dependencies for esbuild

As we use esbuild to build and bundle our APIs, we need to add `swagger-ui-dist` to the `external` list in `esbuild.json` for our SwaggerUI to work in a production build.




---

[Next Page](/llms-full.txt/1)

