Instructions for e-service developers

HarID uses OpenID Connect with OAuth 2.0 protocol (YouTube short intro) for authentication and authorization. For security implications of getting the implementation correct, we require you to use OAuth 2.0 libraries when interacting with HarID endpoints. Best practice would be to use well written code provided by others - it will help you protect yourself and your users.
 

E-service registration

Before you can start sending OpenID/OAuth requests, you have to register your e-service.
Please contact with HarID support (harid@tugi.edu.ee) and provide following information:

1. Your organization name and registration number.
2. Your E-service return urls where HarID forwards back (you can add multiple urls if needed).

After that we can add you to our test-environment (test.harid.ee) and provide you with our OpenID client credentials.


Quick technical configuration parameters in JSON format

Test environment (GET request): https://test.harid.ee/.well-known/openid-configuration
Live environment (GET request): https://harid.ee/.well-known/openid-configuration

OpenID/OAuth technical info

Technical configuration parameters in JSON format:

You can get the latest info for test environment at (GET request) : https://test.harid.ee/.well-known/openid-configuration
You can get the latest info for live environment at (GET request): https://harid.ee/.well-known/openid-configuration

{
    "issuer": "https://harid.ee",
    "authorization_endpoint": "https://harid.ee/et/authorizations/new",
    "jwks_uri": "https://harid.ee/jwks.json",
    "response_types_supported": [
        "code", "token", "id_token", "code token", "code id_token", "id_token token", "code id_token token"
    ],
    "subject_types_supported": [ "public" ],
    "id_token_signing_alg_values_supported": [ "RS256" ],
    "token_endpoint": "https://harid.ee/et/access_tokens",
    "userinfo_endpoint": "https://harid.ee/et/user_info",
    "registration_endpoint": "https://harid.ee/et/connect/client",
    "scopes_supported": [
       "personal_code", "phone", "email", "profile", "openid", "roles", "session_type"
    ], "grant_types_supported": [ "authorization_code", "implicit" ],
    "request_object_signing_alg_values_supported": [ "HS256", "HS384", "HS512" ],
    "token_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ],
    "claims_supported": [ "sub", "iss", "name", "email", "phone_number", "personal_code", "roles" ]
}

 

Data attributes

Exchange code for access token and ID token:

access_token

A token that can be sent to HarID.

id_token

Identity information (JWT) about the user that is digitally signed by HarID.

expires_in

The remaining lifetime of the access token.

token_type

Identifies the type of token returned. At this time, this field always has the value 'Bearer'.

 

Obtain user information from the ID token:

Example response in json format:

{
  "sub": "5727bdad-6f71-4b99-8730-6d66170afa41",
  "name": "Example User",
  "given_name": "Example",
  "family_name": "User",
  "email": "user@example.com",
  "email_verified": true,
  "personal_code": "EE:EID:50701124378",
  "personal_code_verified": true,
  "strong_session": false,
  "roles": [
    {
      "marker": "student",
      "active": true,
      "start_date": "2018-01-17",
      "end_date": null,
      "name_et": "Õpilane",
      "name_en": "Student",
      "name_ru": "student",
      "desc_et": null,
      "desc_en": null,
      "desc_ru": null,
      "provider_ehis_id": "293",
      "provider_reg_nr": "75014445",
      "provider_name": "Keila ühisgümnaasium",
      "created_at": "2018-01-17T16:25:50+02:00",
      "updated_at": "2018-01-17T16:27:55+02:00",
      "student_grade": "6",
      "student_parallel": "A"
    },
    {
      "marker": "faculty",
      "active": null,
      "start_date": "2018-10-09",
      "end_date": null,
      "name_et": "faculty",
      "name_en": "Faculty",
      "name_ru": "faculty",
      "desc_et": null,
      "desc_en": null,
      "desc_ru": null,
      "provider_ehis_id": "223",
      "provider_reg_nr": "75012452",
      "provider_name": "Ääsmäe põhikool",
      "created_at": "2018-10-09T13:44:13+03:00",
      "updated_at": "2018-10-09T13:44:13+03:00"
    },
    {
      "marker": "library-walk-in",
      "active": null,
      "start_date": "2018-10-09",
      "end_date": null,
      "name_et": "library-walk-in",
      "name_en": "Library-walk-in",
      "name_ru": "library-walk-in",
      "desc_et": null,
      "desc_en": null,
      "desc_ru": null,
      "provider_ehis_id": null,
      "provider_reg_nr": "75012452",
      "provider_name": "Ääsmäe põhikool",
      "created_at": "2018-10-09T13:44:13+03:00",
      "updated_at": "2018-10-09T13:44:13+03:00"
    },
    {
      "marker": "student",
      "active": true,
      "start_date": "2018-12-13",
      "end_date": null,
      "name_et": "student",
      "name_en": "Student",
      "name_ru": "student",
      "desc_et": null,
      "desc_en": null,
      "desc_ru": null,
      "provider_ehis_id": "214",
      "provider_reg_nr": "75004429",
      "provider_name": "Albu põhikool",
      "created_at": "2018-12-13T14:42:40+02:00",
      "updated_at": "2018-12-14T19:13:54+02:00",
      "student_grade": "5",
      "student_parallel": null
    }
  ],
  "ui_locales": "et",
  "custodies": [
    {
      "name": "Hernes Hernes",
      "given_name": "Hernes",
      "family_name": "Hernes",
      "email": "priit.tark+020@gmail.com",
      "email_verified": true,
      "personal_code": "EE:EID:60005050011",
      "personal_code_verified": false,
      "roles": [
        {
          "marker": "student",
          "active": true,
          "start_date": "2018-12-13",
          "end_date": null,
          "name_et": "Õpilane",
          "name_en": "Student",
          "name_ru": "student",
          "desc_et": null,
          "desc_en": null,
          "desc_ru": null,
          "provider_ehis_id": "214",
          "provider_reg_nr": "75004429",
          "provider_name": "Albu põhikool",
          "created_at": "2018-12-13T14:42:40+02:00",
          "updated_at": "2018-12-14T19:13:54+02:00",
          "student_grade": "5",
          "student_parallel": null
        }
      ]
    },
    {
      "name": "Loos Loos",
      "given_name": "Loos",
      "family_name": "Loos",
      "email": "priit.tark+011@gmail.com",
      "email_verified": true,
      "personal_code": "EE:EID:38612232328",
      "personal_code_verified": false,
      "roles": [

      ]
    }
  ]
}
}


NB! If client does not require scope, HarID does not return scope attributes.


All attributes:

Scope Attribute Description
openid

sub

Required scope, always include it. An identifier for the user, unique for HarID accounts and never reused. HarID account can have multiple emails at different points in time, but the sub value is never changed. Use sub within your e-service as the unique-identifier key for the user. Example: {"sub": "5727bdad-6f71-4b99-8730-6d66170afa41"}

profile

name

Always present, user's full name. User's full name in displayable form including all name parts: given name, middle name, family name. When visitor_account is true, then name is unverified and visitor can alter name without strong verification.

profile given_name Always present, user first name. Given name(s) or first name(s) of the User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters.
When visitor_account is true, then given_name is unverified and visitor can alter given_name without strong verification.
profile middle_name Optional, user middle name. Middle name(s) of the User. Note that in some cultures, people can have multiple middle names; all can be present, with the names being separated by space characters. Also note that in some cultures, middle names are not used.
When visitor_account is true, then middle_name is unverified and visitor can alter middle_name without strong verification. (not implemented, will come with the visitor support)
profile family_name Always present, user last name. Surname(s) or last name(s) of the User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters.
When visitor_account is true, then family_name is unverified and visitor can alter family_name without strong verification.
profile gender Optional. User's gender. Values defined by this specification are female, male or empty.
When visitor_account is true, user can alter this attribute without strong verification.
(not implemented, will come with the visitor support)
profile birthdate Optional, User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format.
When visitor_account is true, then birthdate is unverified and visitor can alter birthdate without strong verification. (not implemented, will come with the visitor support)
profile updated_at Always present,  time the End-User's information was last updated. The time is represented as the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. (not yet implemented, will come with the visitor support)
profile ui_locales Indicates user preferred user interface locales, example: 'et' for Estonia or 'et en' where Estonia would be preferred over English.
email

email

The user's email address. This may not be unique and is not suitable for use as a primary key. Provided only if your scope included the string "email".

email

email_verified

True if the user's e-mail address has been verified; otherwise false.

personal_code

personal_code

Mostly Estonia's identity code. Always have prefix with 2 colons. Example EE:EID:11412090004 User cannot alter personal code. Personal code are stored only through strong verification.
When visitor_account is true, then personal_code is empty.
personal_code personal_code_verified When visitor_account is true, then personal_code is empty and personal_code_verified is false.
session_type strong_session

True if user user last authentication into HarID was done by using strong authentication method such as Mobile-ID or ID-card. You can use standard way by ID token where "arm" value is either "pwd" (password auth) or "pop" (mobiil-ID/ID-card auth).

phone phone_number User phone number in format "+372 12345678" where phone starts with calling code with "+" sign.
phone phone_number_verified True if user has created an account using strong Mobile-ID authentication. User can alter non Mobile-ID account phone number.
roles roles User roles, user can have multiple roles

roles

roles:marker Unique identifier of user role.

'director' => Provider/school director

'faculty' => Provider/school teacher

'student' => Provider/school student

'secretary' => Provider/school secretary

'sysadmin' => Provider/school sysadmin


Three roles are assigned automatically based on EHIS database with following map:
EHIS role 'õpilane' => HarID role 'student'
EHIS role 'õpetaja' => HarID role 'faculty'
EHIS role 'direktor' => HarID role 'director'
Provider sysadmin/secretary can manage user roles directly in HarID portal without EHIS change.
 

roles

roles:active Defines, if role is valid. Only roles with value "true"  are valid.
Please always check active status because HarID sends also inactive roles. Keep in mind that roles can become inactive temporarily.

roles

roles:start_date Role start date. Start date does not define alone, if role is active. Role must be also active with value "true" and start date must be in past to determine you can rely on it.

roles

roles:end_date Role end date. End date does not define alone, if role is active. Role must be also active with value "true" and end date must missing or in the future.

roles

roles:name_et Role name in Estonian

roles

roles:name_en Role name in English

roles

roles:name_ru Role name in Russian

roles

roles:desc_et Role description in Estonian

roles

roles:desc_en Role description in English

roles

roles:desc_ru Role description in Russian

roles

roles:provider_reg_nr Provider's (institution (school)) registration number

roles

roles:provider_name Provider (example school) name

roles

roles:created_at Role creation time, format: ISO8601

roles

roles:updated_at Role updated time, format: ISO8601

roles

roles:student_grade Only present when user has 'student' role, provides grade, example value: '6'

roles

roles:student_parallel

Only present when user has 'student' role, provides class parallel info, example: 'A'

custodies name String, full name
custodies given_name First name
custodies family_name Family name
custodies email Email
custodies email_verified Boolean, true or false, Child has verified his/her email
custodies personal_code Child personal code
custodies roles Same attributes as main role attributes.

 

NB! If client does not require scope, HarID does not return scope attributes. 

NB! During development, when you change scopes, we recommend to log in to HarID and manually remove all previous confirms.

 

Visitor account support

HarID team is implementing a new visitor's account support, where school's sysadmin or secretary can invite visitors by simple email invitation. Visitor support is made for foreigners, who don't have any strong authentication using Estonia ID/Mobile-ID/SmartID or TARA. Visitor account is similar how currently parent is inviting own child by email with only difference that visitor has empty personal code attribute.

Keep in mind, that visitor can become regular user after visitor start using TARA or having Estonia ID card. Then visitor_account will return false and personal code is present. However many foreign countries do not have personal code, therefor without personal code, those account will be visitors forever.

In short:
1) Please add a scope "visitor" to your authentication request in order to declare your e-service is supporting visitor's account. When you don't use scope "visitor", then HarID portal will inform visitor that your e-service is not supporting visitor's account and HarID portal does not redirect visitor to your e-service.
2) Visitor's account "personal_code" is empty and you cannot use personal code to bind users. You should use "sub" value for binding HarID visitors with your e-service accounts. Sub value is an identifier for the user, unique for HarID accounts and never reused. Use sub within your e-service as the unique-identifier key for the user. Sub value is present for all HarID users. Example: {"sub": "5727bdad-6f71-4b99-8730-6d66170afa41"}
3) Visitor's absolute minimum profile always has: sub, email, given name and family name. All other attributes might not be present.

Visitor scope attributes:

Scope Attribute Description
visitor visitor_account Always present. true if personal_code is blank, otherwise false. Keep in mind, that visitor can turn into user after visitor has bindid account with any strong verification what provides personal_code.
visitor country Optional. User unverified primary country of origin in ISO 3166-1 format. Brazil example: "BR"


NB! Keep in mind that visitor account's given name, middle name, family name, gender, birthdate are user changable! As soon visitor converts visitor account to verified account by strong authentication, user is not able to change those attributes any more. User account cannot convert to vistior's account. Therefore be careful in systems where users's name is important because HarID does not verify visitors name and only users account names are verified.


OpenID/OAuth technical error description

Error name

Error description and debug info

insufficient_scope

Insufficient scope error are returned from user_info request. It means e-service request are denied. Any following situation might cause it:
1) E-service has not requested any scopes, thus HarID does not return any info.
2) E-service has not requested mandatory 'openid' scope. Double check your system has requested at least 'openid' scope.
3) E-service has done everything right but end user has denied giving info out. Please login into HarID portal and remove all E-service authorizations because during testing/development you might previously have denied authorization thus HarID refuse to return requested info.

It the future, when your e-service change scopes, then all your users current authorizations will be canceled automatically and all your users must authorize your e-service new scopes.



OpenID/OAuth technical low-level flow for debugging

You can test/play with a demo client at https://kool.domify.io

HarID service only supports official OAuth 2.0 libraries  We provide low-level flow in order to better understand and debug OpenID Connect protocol.

Terms:

  • client - Demo Pihlaka school at https://kool.domify.io
  • HarID - Demo HarID server at https://rharid.domify.io


1. User visits client website and clicks HarID button. Client system will redirect user to HarID system. Please follow protocol defined at RFC6749 4.1.1 Authorization Request. Include all requested scopes (dark text):

GET redirect request:
https://test.harid.ee/et/authorizations/new?client_id=a6095bd2e837af2ef8c69ee87d7028d8&nonce=0d790445152f8b8bca5a847170e987b5&redirect_uri=https%3A%2F%2Fkool.domify.io%2Fproviders%2F2%2Fopen_id&response_type=code&scope=openid+profile+email+personal_code+roles+session_type+custodies&state=0d790445152f8b8bca5a847170e987b5

NB! The nonce you provide is required to verify by your system at later steps. More info at the OpenID connect core spec and a security explanation.
 

2. User logs in to HarID and grant permissions for the authorization request. HarID redirect user back to client following redirect url (redirect url must register before at HarID support).

3. Client system makes GET request  "https://harid.domify.io/.well-known/openid-configuration" and gets where to make Access Token request. Client makes access_token request.

POST /et/access_tokens HTTP/1.1
Authorization: Basic MWViNTJjNDc0MmUyNzBkY2ZiNzA5NjYzNjVhNzUwOWM6MWQ0ODZlODk0NjVmZmM0MmIxZDliNTc0OTU4MThlNzJhMmExYTgxNjNhNWM1ZDFhMDY1NTc4ZGQyYjY0MmMyZA==
Content-Type: application/x-www-form-urlencoded
Content-Length: 167
Host: rharid.domify.io

grant_type=authorization_code&code=7677a231beefcc80465c71d15766caa3ff8c5fc3789f45e7c03569fdf27436cc&redirect_uri=https%3A%2F%2Fkool.domify.io%2Fproviders%2F1%2Fopen_id

HarID returns access_token:

GET /et/user_info? HTTP/1.1
Authorization: Bearer 981574fe1aeba078a767329e7fcd354da48ee2bfe4440a365b534690c5b9f494
Host: harid.domify.io

Status: 200 OK
Content-Type: application/json
Connection: keep-alive
Status: 200 OK
Cache-Control: no-store
Strict-Transport-Security: max-age=31536000
Pragma: no-cache
X-Request-Id: 46f4bcca-05f5-4b49-9197-4522f4365f58
ETag: W/"28b332d4c5e80bf8641b4710aa339e6a"
X-Runtime: 0.071670
Date: Tue, 14 Apr 2020 08:10:10 GMT
X-Powered-By: Phusion Passenger 6.0.4
Server: nginx/1.14.2 + Phusion Passenger 6.0.4
Content-Length: 0

{"access_token":"981574fe1aeba078a767329e7fcd354da48ee2bfe4440a365b534690c5b9f494","token_type":"bearer","expires_in":86399,"id_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHQifQ.eyJpc3MiOiJodHRwczovL2hhcmlkLmdpdGxhYi5ldSIsInN1YiI6ImU4NmVmNTkyLTkyNjItNDg5Zi05YmQxLTE0OTA5ZDE3MmQ4OSIsImF1ZCI6IjFlYjUyYzQ3NDJlMjcwZGNmYjcwOTY2MzY1YTc1MDljIiwiZXhwIjoxNTg2ODUyMTEwLCJpYXQiOjE1ODY4NTE4MTAsIm5vbmNlIjoiOTYwOTE5YmQyMDVhMDU0ODAyYzZkODhlOGRmYjk5YTkiLCJhbXIiOiJbXCJwd2RcIl0ifQ.MsQ7xdNMBw2uU1IeikvZ5AVq00UVl7JInKhRGeGc5vwcogGSkFL3293zT1KGveDSJbSZG9IwffuMqZX_OLhbh-xLExSkvOHe3CdOlCQHq3O0bdxlCgZVelzzOaXSO5274Uj-SMsA-cCqKYqoh5v2SH5ZcG5-I6XwMJV_wsmvUJccvv-vkC_ConI8rTjUi2S0rGBK0tm-AIksY0T6GOA0odd0lo_XmOrY60GjXt-t2PDvg6dFytiJOPykjtlQYywsanBgqvzk2HWkcY51DMKd3930urirehwOW-HEfVERB1cD3TBktVpxVXICLzHZHANe3MwJJYw8n5huMBcK4PX6zA"}


4. Client makes now user_info request with access_token as follows:

GET /et/user_info? HTTP/1.1
Authorization: Bearer 981574fe1aeba078a767329e7fcd354da48ee2bfe4440a365b534690c5b9f494
Host: rharid.domify.io

HarID returns:

Status: 200 OK
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Status: 200 OK
Cache-Control: max-age=0, private, must-revalidate
Strict-Transport-Security: max-age=31536000
X-XSS-Protection: 1; mode=block
X-Request-Id: 9088d5ac-755f-4079-8f7f-b349ae4eedf9
ETag: W/"676467cd54d2594efb6ef312f05a7ada"
X-Frame-Options: SAMEORIGIN
X-Runtime: 0.033594
X-Content-Type-Options: nosniff
Date: Tue, 14 Apr 2020 08:10:10 GMT
X-Powered-By: Phusion Passenger 6.0.4
Server: nginx/1.14.2 + Phusion Passenger 6.0.4
Content-Length: 0

{"sub":"e86ef592-9262-489f-9bd1-14909d172d89","name":"Priit Test","given_name":"Priit","family_name":"Test","email":"priit@example.com","email_verified":true,"personal_code":"EE:EID:34501234215","strong_session":false,"roles":[{"marker":"sysadmin","active":true,"start_date":"2019-08-12","end_date":null,"name_et":"sysadmin","name_en":"sysadmin","name_ru":"sysadmin","desc_et":null,"desc_en":null,"desc_ru":null,"provider_ehis_id":null,"provider_reg_nr":"75002426","provider_name":"Aakre lasteaed-algkool","created_at":"2019-08-12T15:24:49+03:00","updated_at":"2019-08-12T15:25:27+03:00","student_grade":null,"student_parallel":null},{"marker":"secretary","active":true,"start_date":"2020-01-06","end_date":null,"name_et":"secretary","name_en":"secretary","name_ru":"secretary","desc_et":null,"desc_en":null,"desc_ru":null,"provider_ehis_id":null,"provider_reg_nr":"123","provider_name":"Rapla  Gümnaasium","created_at":"2020-01-06T11:17:51+02:00","updated_at":"2020-01-06T11:18:16+02:00","student_g
rade":null,"student_parallel":null},{"marker":"student","active":null,"start_date":"2020-02-12","end_date":null,"name_et":"student","name_en":"Student","name_ru":"student","desc_et":null,"desc_en":null,"desc_ru":null,"provider_ehis_id":null,"provider_reg_nr":"75002426","provider_name":"Aakre lasteaed-algkool","created_at":"2020-02-12T16:12:51+02:00","updated_at":"2020-02-12T16:12:51+02:00","student_grade":null,"student_parallel":null},{"marker":"student","active":null,"start_date":"2020-02-12","end_date":null,"name_et":"student","name_en":"Student","name_ru":"student","desc_et":null,"desc_en":null,"desc_ru":null,"provider_ehis_id":null,"provider_reg_nr":"75002426","provider_name":"Aakre lasteaed-algkool","created_at":"2020-02-12T16:13:20+02:00","updated_at":"2020-02-12T16:13:20+02:00","student_grade":null,"student_parallel":null}],"ui_locales":"et","custodies":[]}