Passa al contenuto principale

Overview

auth service authenticates users with SMS codes.

Configuration

Configuration is passed to the service as ENV variables. Please refer to the /internal/config/config.go file for a complete list of all supported configuration variables and their description.

Errors

Auth service API returns errors in JSON format with a corresponding HTTP response status code. The returned JSON object tries to describe the problem with a human-readable message and includes a few additional attributes which can help clients handle the error in a more sensible way. Below is an example error:

HTTP 403 Forbidden

{
"id": "...",
"kind": 3,
"errorCode": "file_too_large"
"message": "uploaded file is 23423 bytes above the configured file size limit",
}
  • id is unique error identifier
  • kind is an integer value that describes the error kind. Often it directly corresponds to the returned HTTP response status code, but is included in the JSON object to allow better handling of the error when it is propagated to internal components outside the transport layer. Also, some transport layers like gRPC may not use HTTP status codes.
  • errorCode is an optional string value which may be useful for frontend clients to determine what kind of localized/translated error message to show on the screen for users. Think of it as a subtype of the more generic error type: 403 Forbidden -> file_too_large

Without this attribute, a frontend client which may receive HTTP 403 Forbidden in many different cases/requests will have to search for clues inside the message string to determine how to handle each separate case (not pretty).

  • message is human-readable description of the problem which is suitable for storing in log outputs and can help system administrators/testers/developers debug issues more easily.

Error codes

Here is a list of the currently defined error codes returned in error responses. Please update the table when you add new error code definitions.

errorCodedescription
expired_codeVerification code is correct, but has expired.
incorrect_codeVerification code is incorrect or not found.
invalid_emailInvalid email address.
invalid_mobileInvalid mobile phone number.
invalid_code_or_emailInvalid verification code or email.
invalid_bcc_addressInvalid BCC address when replying.
email_mismatchNormalized BCC address when replying is different from authenticated user email.
unauthorized_userThe given mobile number or email address are not authorized to read the message.
forbidden_auth_methodAttempted authentication method is forbidden for this recipient.
forbidden_file_typeUploaded attachment file type is forbidden.
malware_detectedUploaded attachment file may contain malware.
file_too_largeUploaded attachment file is too large.
upload_limit_reachedUploaded attachment file is above the total size limit for reply.
new_mobile_conflictThe new mobile number is the same as the old phone number.
sms_rate_limitSMS rate limiter prevents the sending of new sms.
email_and_mobile_mismatchMobile number and email address are not matching.

Functionalities

Keep me signed in

The service supports the "keep me signed in" feature. When a user authenticates with the keep me signed in option checked, the service will set a cookie with positive Max-Age value (the lifetime of the cookie in seconds) which allows the browser to persist the cookie even after the browser is closed. This allows the user to stay signed in until the cookie expires, is deleted or the user logs out.

For the cookie to be persisted, the RememberMe function should be called with the true argument.

Logout

The service provides GET /logout endpoint. When the browser send a logout request, the service deletes any session information and sets a cookie with an empty value and a negative Max-Age value, causing the browser to discard it immediately.

mTAN (Mobile transaction authentication number)

The service supports the mTAN functionality. When a user authenticates with a mobile number, a one-time password (OTP) code is securely generated, stored in session and sent to the user's mobile number. The user must provide the OTP code to authenticate successfully.

Send SMS

The service supports sending SMS messages to users. It uses an external service provider's API to send SMS messages. The provider's address and credentials are passed to the service as environment variables.

SMS Code Expiration

// CodeExpiration defines the time for a verification code to expire.
CodeExpiration time.Duration `envconfig:"SMS_CODE_EXPIRATION" default:"15m"`

This setting defines the time limit for how long an SMS verification code remains valid. If the code is not used within this time frame, it will expire, and the user will need to request a new one. The default expiration time is 15 minutes.

Unsent Attachment Files Retention

Users can reply to Sealed emails and attach files to the reply. The files are stored by the Auth service and are kept for some period of time if the Reply is not sent. This enables Draft functionality, where users can continue the reply later on another device.

The following two variables define the retention functionality of attachments in case the reply is initiated, but is never completed/sent by the user. This is required, so that Auth storage is not filled-up with unnecessary files, which are never to be sent.

ATTACHMENTS_RETENTION_PERIOD="336h" specifies how long attachment files must be kept, before becoming eligible for delete. This is defined as string in hours, and guarantees that files shall not be removed during this period.

EXPIRED_ATTACHMENTS_WATCHER_INTERVAL="1h" specifies the interval at which a separate async process (e.g. something like cronjob) will look for expired attachments and delete them. This interval plus the retention period defines the maximum amount of time for storing attachments files, before they are deleted.

An example: if retention is 1 minute and the interval for cleaning unsent attachments is 1 hour, then the maximum time an attachment can be kept in storage is 61 minutes.

A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".

Storage

The service uses PostgreSQL for relational storage and S3-compatible buckets for attachment files used in replies.

DB migrations

SQL migration files are created in /db/migrations by using the Golang migrate tool. Example command to make a new migration file:

migrate create -ext sql -dir ./db/migrations messages_table

Metrics

The service exposes the following Prometheus metrics.

Metric NameType
http_requests_totalCounter with labels [operation, code]
http_request_duration_secondsHistogram with labels [operation, code]
sent_sms_messages_totalCounter

CSRF Token Handling

When making a GET request to the following endpoints:

  • /v1/config
  • /v1/message/files

The response will include an X-CSRF-Token header. This token must be saved and used in all subsequent POST, PUT, and DELETE requests. The request itself must also contain the X-CSRF-Token header with the token you received.

How to Use

  1. Get the Token
    • Send a GET request to /v1/config or /v1/message/files.
    • Save the value of the X-CSRF-Token header.
  2. Include the Token in Requests

For POST, PUT, and DELETE requests, include the X-CSRF-Token in the headers like this:

X-CSRF-Token: {your-token}

Example

POST /v1/your-endpoint
X-CSRF-Token: {your-token}
Content-Type: application/json

{
"data": "your-payload"
}

Dependencies and Vendor

The project uses Go modules for managing dependencies and we commit the vendor directory. When you add/change dependencies, be sure to clean and update the vendor directory before submitting your Merge Request for review.

go mod tidy
go mod vendor

To understand why we commit the vendor directory, please refer to Vendor or not to vendor.

Tests and Linters

Test

To execute the units tests for the service go to the root project directory and run:

go test -race ./...

Linters

To run the linters go to the root project directory and run:

golangci-lint run