# Opinsys Authentication

To implement Opinsys Authentication to an external service, you must receive a shared secret from Opinsys support at `tuki @ opinsys.fi`. To receive it, you must provide us the following information:

- Fully qualified domain name (FQDN)
  - The service must be available on this domain
- Name and a short description of the service
  - Will be displayed on the login form and admin configuration panel for school admins
- Email address of the service maintainer
- Optionally, a path prefix for the service. Required only if multiple external services must be served from the same domain with different shared secrets
- Optionally, a link describing the service in more detail

Once the shared sercret is in place, the external service may redirect the user's web browser to `https://api.opinsys.fi/v3/sso` with a `return_to` query string key which determines where the user will be redirected back. The hostname of the `return_to` URL must match the FQDN provided to us.

Example redirect URL might be:

    https://api.opinsys.fi/v3/sso?return_to=http%3A%2F%2Fexample.com

When a user is authenticated he/she will be redirected to the URL specified in the `return_to` query string key. The URL is augmented with a `jwt` query string key which will contain a JSON Web Token. The external service is expected to decode this token, validate it with the given shared secret and make sure that it is not issued too long a ago or in the future. The token will contain following claims:

- `iat` Identifies the time at which the JWT was issued as Unix timestamp
- `jti` A unique identifier for the JWT
- `id` Unique identifier for the user
- `username`
- `first_name`
- `last_name`
- `email` User email
  - Not always available!
- `primary_school_id`
  - The school id user primarily attends to
- `schools` List of schools the user belongs to
  - `id` Unique identifier for the school
  - `name` Human-readable school name
  - `abbreviation` Valid POSIX name for the school
  - `school_code` The Finnish school code. Can be `null` if it hasn't been specified. Not all schools have this set.
  - `roles` One or more (there should always be at least one) roles the user has in this school. An array of strings, possible values are:
    - `teacher`, `staff`, `student`, `visitor`, `parent`, `admin`, `schooladmin` and `testuser`
  - `groups` List of groups the user has in the school:
    - `id` Unique identifier for the group
    - `name` Human-readable group name
    - `abbreviation` Valid POSIX name for the group
    - `type` Type of the group. Either `null` (if the type is unspecified) or one of these:
      - `teaching group`, `year class`, `administrative group`, `course`, `archive users` or `other groups`
  - `learning_materials_charge`
    - The value of the MPASS' `learningMaterialsCharge` attribute for this user in this school. Omitted if the value is not known for this school ("best effort"). When specified, it is formatted as `X;YYYYY` where X is either 0 or 1, and YYYYY is the school code. More information here (in Finnish).
- `organisation_name`
  - Human-readable organisation name.
- `organisation_domain`
  - For example `jyvaskyla.opinsys.fi`.
- `learner_id`
  - The 11-digit Finnish national learner ID, prefixed with the OID "1.2.246.562.24.". Read this for more information. Can be `null` if the ID has not been set.

In addition to those above, there are some "extra" fields that can be used, but you should NOT rely on their presence (they might not always exist). They are:

- `puavo_id`
  - This is the actual internal unique ID for this user. It is the same as `id`, but this field gives it an explicit name.
- `external_id`
  - External IDs (social security number hash for Primus users) for users who attend a school that has Primus integration enabled. Will be `null` for others.
- `preferred_language`
  - Two-letter language code (`en`, `fi`, `sv`, `de` and so on) identifying the language this user primarily speaks. Can be used to localize the environment.
- `year_class`
  - A string containing the year class name for students who attend a school that has Primus integration enabled. Will be always `null` for non-students and students who are not in a Primus-enabled school.
- `user_type`
  - Please ignore this. It is an obsolete field containing the "first" role the user has. This field exists only for backwards compatibility; using it for anything is almost certainly a mistake. If you need the user's roles, look them up in the `schools` array as described above.

## Service activation

By default external services are not activated for all Opinsys organisations. Each organisation or individual schools must activate the external services on their behalf. They can do this directly from their management interface.

## Organisation presetting

If the external service knows in advance from which organisation the user is coming from it can make the login a bit easier by specifying an additional query string key `organisation` to the redirect URL:

    https://api.opinsys.fi/v3/sso?organisation=kehitys.opinsys.fi&return_to=http%3A%2F%2Fexample.com

Then users don't have to manually type their organisation during login.

## Kerberos

When the user is coming from a Opinsys -managed desktop, Kerberos will be used for the authentication. The user will not even see the Opinsys login form in this case. He/she will be directly redirected back to `return_to` URL with a `jwt` key. The organisation presetting is ignored when Kerberos is active because the organisation will be read from the Kerberos ticket. This is enabled by default for all external services using Opinsys Authentication.

## Custom fields

If you need to relay some custom fields through the Authentication service you can just add them to the `return_to` URL. Just remember to escape the value.

Example:

    https://api.opinsys.fi/v3/sso?return_to=https%3A//example.com/path%3Fcustom_field%3Dbar

Redirects user to:

    https://example.com/path?custom_field=bar&jwt=<the jwt token>

## Implementation help

- JSON Web Token draft
- Known working JSON Web Token implementations
  - For Ruby
  - For node.js

Feel free to contact us at `dev @ opinsys.fi` or open up an issue on Github if you have any trouble implementing this. If you think this documentation could be improved, contact us.