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",
}
idis unique error identifierkindis 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.errorCodeis 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).
messageis 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.
| errorCode | description |
|---|---|
| expired_code | Verification code is correct, but has expired. |
| incorrect_code | Verification code is incorrect or not found. |
| invalid_email | Invalid email address. |
| invalid_mobile | Invalid mobile phone number. |
| invalid_code_or_email | Invalid verification code or email. |
| invalid_bcc_address | Invalid BCC address when replying. |
| email_mismatch | Normalized BCC address when replying is different from authenticated user email. |
| unauthorized_user | The given mobile number or email address are not authorized to read the message. |
| forbidden_auth_method | Attempted authentication method is forbidden for this recipient. |
| forbidden_file_type | Uploaded attachment file type is forbidden. |
| malware_detected | Uploaded attachment file may contain malware. |
| file_too_large | Uploaded attachment file is too large. |
| upload_limit_reached | Uploaded attachment file is above the total size limit for reply. |
| new_mobile_conflict | The new mobile number is the same as the old phone number. |
| sms_rate_limit | SMS rate limiter prevents the sending of new sms. |
| email_and_mobile_mismatch | Mobile 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 Name | Type |
|---|---|
| http_requests_total | Counter with labels [operation, code] |
| http_request_duration_seconds | Histogram with labels [operation, code] |
| sent_sms_messages_total | Counter |
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
- Get the Token
- Send a GET request to
/v1/configor/v1/message/files. - Save the value of the
X-CSRF-Tokenheader.
- Send a GET request to
- 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
vendordirectory, 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