Authentication Service Configuration
The Authentication Service needs some environment variables, and a configurations file to work.
Environment variables
The environment variables needed by the service are:
- LOG_LEVEL (default: info): level of the log. It can be trace, debug, info, warn, error, fatal or silent
- HTTP_PORT (default: 8080): http port exposed by the service;
- SERVICE_PREFIX (optional): the prefix used for the path of the service endpoints (except for the metrics and health endpoints);
- DELAY_SHUTDOWN_SECONDS (default: 10): the amount of seconds waited before closing the service when performing a graceful shutdown;
- REDIS_MODE (default:
normal
, introduced inv3.5.0
): defines the redis mode (normal
orsentinel
); - REDIS_HOSTS (required): a comma-separated list of the Redis hosts; The hosts must be in the form
ipaddress:6379
. WhenREDIS_MODE=normal
, specify only one host; - REDIS_HOST ( DEPRECATED since
v3.5.0
, required ifREDIS_HOSTS
is not set): the Redis host, with the port; this is deprecated: useREDIS_HOSTS
instead. It is still supported for retro-compatibility only whenREDIS_MODE=normal
; - REDIS_USERNAME (optional): the username to authenticate to Redis. Leave blank if the server does not require authentication.
- REDIS_PASSWORD (optional): the password to authenticate to Redis. Leave blank if the server does not require authentication.
- REDIS_MASTER_NAME (required if
REDIS_MODE=sentinel
): the name of the master of your Redis Sentinel configuration - REDIS_TLS (optional): if
true
, enable the TLS connection to Redis. Default isfalse
; - REDIS_TLS_CACERT (optional): the path to the CA of the Redis server, if it's not public (this is effective only if
REDIS_TLS
is set totrue
); - CONFIG_FILE_PATH (required): the path to the configuration file. Do not include the file name;
- CONFIG_FILE_NAME (required): the name of the JSON configuration file. Do not include the extension;
- USERS_CRUD_BASE_URL (required): base URL of the internal endpoint of the CRUD service exposing the data of the users (e.g.
http://crud-service/users
); - MIA_JWT_TOKEN_SIGN_KEY (optional): required when
MIA_JWT_TOKEN_SIGNING_METHOD
is HS256 (the default value), a JWT signing key used to generate the authentication JWT for the user login (preferred an HMAC of least of 512 bytes); - MIA_JWT_TOKEN_VALID_DURATION_SEC (required): time in seconds before the generated access token expires;
- PROVIDER_TOKEN_PASS_PHRASE (required): a string used to encrypt the JWT (preferred an HMAC at least of 128 bytes);
- MIA_REFRESH_TOKEN_VALID_DURATION_SEC (required): time in seconds before the generated refresh token expires;
- EXPIRE_DELTA_PROVIDER_TOKEN_SEC (optional): how many seconds before the expiration of refresh token will be refreshed automatically;
- ORIGINAL_PROTOCOL_HEADER (required): header containing the protocol of the original request (http or https);
- ADDITIONALS_CA_FOLDER (optional): folder which contains the CA of the OAuth2 identity providers, if it's not public;
- ADDITIONAL_HEADERS_TO_PROXY (optional): comma separated list of headers to proxy to the request to CRUD service.
- STORED_ACCESS_TOKEN_NUMBER (optional): maximum number of stored access token associated to a user. The tokens are stored on Redis. Default is 10.
- REDIS_SESSION_SCOPE (required): a string used to define the scope of redis in order to distinguish items in a multi-tenant architecture.
- STATE_MANAGER_EXPIRATION_TIME_MINUTES (optional): Minutes the state should be maintained during registration, login, etc. Default is 2 minutes.
- MIA_JWT_TOKEN_SIGNING_METHOD (default:
HS256
): The token signing method to be used. Currently supported methods areHS256
(the default) andRS256
- MIA_JWT_TOKEN_PRIVATE_KEY_FILE_PATH (optional): required if MIA_JWT_TOKEN_SIGNING_METHOD is RS256, the file name of the mounted private key, without extension.
- MIA_JWT_TOKEN_PRIVATE_KEY_PASSWORD (optional): The password of the private key. Required only if the private key is password protected.
- MIA_JWT_TOKEN_PRIVATE_KEY_KID (optional): required if MIA_JWT_TOKEN_SIGNING_METHOD is RSA256, the kid of the current private key.
- EXPOSE_METRICS (optional, default:
false
): iftrue
, the service will expose Prometheus metrics on the/-/metrics
endpoint. - NAMESPACED_METRICS_PREFIX (optional, default:
authentication_service
): the prefix to be used for the Prometheus metrics. - INVALID_REFRESH_TOKEN_WIPES_COOKIES (optional, default:
false
): If true, the /refreshtoken endpoint wipes the session cookies in case the provided refresh token is not valid
Configurations file
The configurations file required by the Authentication Service is in the JSON format. The file stores the configurations required by the Identity Providers to be used for authentication of your applications.
We recommend to mount this configuration file using a Kubernetes Secret due its confidential content.
It is important to outline that it is possible to define an order
property, not required, that will order your providers in the providers API result (e.g. for your login page) from the relative highest value to the lowest. In case the order property is not defined or multiple providers have the same order number, the service will alphabetically order them.
For the service configuration, there is an apps
field with as key the appId with value the app configuration.
The app configuration contains:
- providers (required): an object with key the providerId and as value the provider configuration;
- type (required): the type of the provider. Can be
gitlab
,github
,okta
,microsoft
,keycloak
orgeneric
; - clientId (required): the client ID of the OAuth2 app;
- clientSecret (required): the client secret of the OAuth2 app;
- authUrl (required): URL to call the authorize endpoint of the
authorization_code
grant type in the identity provider; - tokenUrl (required): URL to get the token in the identity provider;
- baseUrl (required): base URL of the provider;
- scope (required): an array of string of the scope to forward to the identity provider;
- order (optional): a number which define the order to be returned from the get apps endpoint;
- userSettingsURL (optional): an URL to send the user to the user settings page on idp provider;
- skipRefreshProviderTokenOnMiaTokenRefresh (default
false
): iftrue
, the provider's token won't be refreshed when calling the/refreshtoken
endpoint, unless the provider token has expired; - logoutUrl (optional) (available since
v3.3.0
): If the provider is OIDC compliant, the url where the user agent is redirected to perform the logout from the provider; - exposeProviderIdToken (default:
false
) (available sincev3.9.0
): Only applicable whereprovider.type
ismicrosoft
, when true an endpoint to retrieve the provideridToken
is exposed.
- type (required): the type of the provider. Can be
- redirectUrl (required): the url where the app is redirected during the
authorization_code
grant type, to be redirect after the authorize call. This must be set the same as in the idp provider; - authorizeStateRequired (default:
false
): Whentrue
, the client should generate thestate
parameter, enabling further protection against CSRF attacks. See the related section; - realm: (required): the realm of the application, to aggregate users between different configuration in a same provider (user is identified by realm, providerId and providerUserId*);
- defaultGroups (required): an array of strings to add as group to a user on user creation;
- allowedRedirectUrlsOnSuccessfulLogin (optional): a set of strings with the allowed redirect urls on successful login; do not add the query string here as it will be ignored when checking if the url is allowed, as per the the specification
- defaultRedirectUrlOnSuccessfulLogin (optional): a string to set the default redirect on successful login;
- isWebsiteApp (optional): a boolean, if true set a Cookie sid in header.
- customTokenClaims (optional): options to configure additional custom claims to be added to the JWT token.
- includeProviderUserId (default:
false
): iftrue
, the claimproviderUserId
will be included in the JWT token. - metadataFieldsToInclude (optional): an array of fields to be included under the field
metadata
. Themetadata
field will be populated only if the array is defined and not empty.
- includeProviderUserId (default:
- issuer (required): The value of the
iss
claim, it will be inserted in the issued tokens. - sidCookieCustomAttributes (optional): an object with a sid cookie custom configuration. If not set a default configuration will be applied, more information here
- domain (optional): sets the
Domain
attribute to the cookie to a value of your choice. By default, the attribute is not added. - path (default:
/
): sets thePath
attribute to the cookie to a value of your choice. By default, the value is set to/
. - sameSite (optional): sets the
SameSite
attribute to the cookie, allowed values areLax
andStrict
. By default, the attribute is set toLax
.
- domain (optional): sets the
- refreshCookieCustomAttributes (optional): an object with a sid cookie custom configuration. If not set a default configuration will be applied, more information here
- domain (optional): sets the
Domain
attribute to the cookie to a value of your choice. By default, the attribute is not added. - path (default:
/
): sets thePath
attribute to the cookie to a value of your choice. By default, the value is set to/
. - sameSite (optional): sets the
SameSite
attribute to the cookie, allowed values areLax
andStrict
. By default, the attribute is set toLax
.
- domain (optional): sets the
Here an example of the service configuration:
{
"apps": {
"APP_ID": {
"providers": {
"PROVIDER_ID": {
"type": "gitlab|github|okta|microsoft|bitbucket|keycloak|generic",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "auth_url",
"tokenUrl": "token_url",
"userInfoUrl": "user_info_url",
"baseUrl": "base_url",
"scope": ["custom_scope"],
"order": 10,
"userSettingsURL": "settings-url"
}
},
"authorizeStateRequired": true,
"redirectUrl": "https://test.com/redirect",
"realm": "realm1",
"isWebsiteApp": true,
"defaultGroups": ["users"],
"issuer": "issuer1"
}
}
}
You can retrieve most of the URLs needed for the configuration from the OpenID Connect Discovery URL, usually exposed by the providers under the /.well-known/openid-configuration
route. Refer to the provider documentation.
Users collection
To correctly configure the service, it is important to configure the CRUD collection with the internal endpoint set in the USERS_CRUD_BASE_URL environment variable. Remember also to set the default state of the endpoint to PUBLIC.
Fields in the CRUD collection must be the following:
Field Name | Field Type | Required |
---|---|---|
name | String | ❌ |
groups | Array of string | ❌ |
username | String | ❌ |
String | ❌ | |
providerId | String | ✅ |
providerUserId | String | ✅ |
realm | String | ✅ |
metadata | Object | ❌ |
permissions | Array of string | ❌ |
The fields groups
, providerId
, and realm
are obtained from the service configuration described above.
The metadata
field can be used to store any kind of information about the user.
It is not recommended to store additional fields at the root of the collection, as future versions of the authentication service could introduce new fields with clashing names.
Nest any additional information about the user under the metadata
field.
In order to simplify and speedup the setup of Users collection, here it is provided its definition ready to be imported in the CRUD page of Console design section.
Users Collection Definition (import ready)
{
"data": {
"collections": {
"users": {
"id": "users",
"description": "Collection of users",
"name": "users",
"tags": [
"collection"
],
"fields": [
{
"name": "_id",
"description": "_id",
"type": "ObjectId",
"required": true,
"nullable": false
},
{
"name": "creatorId",
"description": "creatorId",
"type": "string",
"required": true,
"nullable": false
},
{
"name": "createdAt",
"description": "createdAt",
"type": "Date",
"required": true,
"nullable": false
},
{
"name": "updaterId",
"description": "updaterId",
"type": "string",
"required": true,
"nullable": false
},
{
"name": "updatedAt",
"description": "updatedAt",
"type": "Date",
"required": true,
"nullable": false
},
{
"name": "__STATE__",
"description": "__STATE__",
"type": "string",
"required": true,
"nullable": false
},
{
"name": "name",
"type": "string",
"required": false,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"name": "groups",
"type": "Array_string",
"required": false,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"name": "username",
"type": "string",
"required": false,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"name": "email",
"type": "string",
"required": false,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"name": "providerId",
"type": "string",
"required": true,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"name": "providerUserId",
"type": "string",
"required": true,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
},
{
"type": "string",
"required": true,
"nullable": false,
"encryptionEnabled": false,
"encryptionSearchable": false,
"sensitivityValue": 0,
"name": "realm"
},
{
"type": "RawObject",
"required": false,
"nullable": false,
"encryptionEnabled": false,
"encryptionSearchable": false,
"sensitivityValue": 0,
"name": "metadata"
},
{
"name": "permissions",
"type": "Array_string",
"required": false,
"nullable": false,
"sensitivityValue": 0,
"encryptionEnabled": false,
"encryptionSearchable": false
}
],
"internalEndpoints": [
{
"basePath": "/users",
"defaultState": "PUBLIC"
}
],
"type": "collection",
"indexes": [
{
"name": "_id",
"type": "normal",
"unique": true,
"fields": [
{
"name": "_id",
"order": 1
}
]
},
{
"name": "createdAt",
"type": "normal",
"unique": false,
"fields": [
{
"name": "creatdAt",
"order": -1
}
]
},
{
"name": "stateIndex",
"type": "normal",
"unique": false,
"fields": [
{
"name": "__STATE__",
"order": 1
}
]
},
{
"name": "nameSearch",
"type": "normal",
"unique": false,
"fields": [
{
"name": "email",
"order": 1
},
{
"name": "name",
"order": 1
},
{
"name": "__STATE__",
"order": 1
}
]
},
{
"name": "upsertSupport",
"type": "normal",
"unique": false,
"fields": [
{
"name": "providerId",
"order": 1
},
{
"name": "providerUserId",
"order": 1
},
{
"name": "realm",
"order": 1
}
]
}
]
}
}
},
"metadata": {
"branchName": "master",
"exportTimestamp": "2024-09-06T12:53:56.133Z",
"isImported": false,
"pathRefType": "revisions",
"projectId": "",
"projectName": ""
}
}
How to configure providers
Below, the different configuration based on provider type.
- GitLab
- GitHub
- Okta
- Microsoft
- Bitbucket Server
- Keycloak
- Generic
This is a configuration example for an app using GitLab Identity provider. Replace {GITLAB_URL}
with the url of your instance (or the public one).
{
"apps": {
"web": {
"providers": {
"gitlab": {
"type": "gitlab",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "https://{GITLAB_URL}/auth",
"tokenUrl": "https://{GITLAB_URL}/token",
"userInfoUrl": "https://{GITLAB_URL}/api/v4/user",
"baseUrl": "https://{GITLAB_URL}",
"scope": ["custom_scope"],
"order": 10,
"userSettingsURL": "settings-url"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
This is a configuration example for an app using GitHub Identity provider. Replace {GITHUB_URL}
with the url of your instance (or the public one).
{
"apps": {
"web": {
"providers": {
"github": {
"order": 20,
"type": "github",
"label": "My GitHub",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "https://{GITHUB_URL}/authorize",
"tokenUrl": "https://{GITHUB_URL}/oauth/token",
"userInfoUrl": "https://{API_GITHUB_URL}/user",
"baseUrl": "https://{API_GITHUB_URL}",
"scope": ["custom_scope_github"],
"userSettingsURL": "settings-url"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
This is a configuration example for an app using Okta Identity provider. Replace {OKTA_BASE_URL}
with the url.
{
"apps": {
"web": {
"providers": {
"okta": {
"order": 30,
"type": "okta",
"label": "Login with Okta",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "{OKTA_BASE_URL}/v1/authorize",
"tokenUrl": "{OKTA_BASE_URL}/v1/token",
"userInfoUrl": "{OKTA_BASE_URL}/v1/userinfo",
"baseUrl": "{OKTA_BASE_URL}",
"scope": ["your_scope"],
"userSettingsURL": "{OKTA_BASE_URL}/enduser/settings"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
This is a configuration example for an app using a generic Microsoft Identity provider.
{
"apps": {
"web": {
"providers": {
"microsoft": {
"type": "microsoft",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
"tokenUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
"userInfoUrl": "https://graph.microsoft.com/oidc/userinfo",
"baseUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/",
"scope": ["openid"],
"order": 10,
"userSettingsURL": "https://account.microsoft.com/profile/"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
Here is an example of configuration of Microsoft's Azure AD B2C identity management service:
{
"apps": {
"web": {
"providers": {
"microsoft": {
"type": "microsoft",
"clientId": "<application-client-id>",
"clientSecret": "<client-secret>",
"authUrl": "https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<signin-policy-name>/oauth2/v2.0/authorize",
"tokenUrl": "https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<signin-policy-name>/oauth2/v2.0/token",
"userInfoUrl": "https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<signin-policy-name>/openid/v2.0/userinfo",
"baseUrl": "https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<signin-policy-name>/oauth2/v2.0/",
"scope": ["openid", "offline_access", "<application-client-id>"]
}
},
"redirectUrl": "https://some-redirect/url",
"realm": "my-realm",
"defaultGroups": ["some_group"],
"issuer": "issuer1",
"isWebsiteApp": true
}
}
}
Please note that for this provider to work you need to create a custom policy that enables the /userinfo
endpoint on Azure portal. The policy must include at least the sign in capability. Please refer to the official documentation for a detailed explanation on how to setup it.
You probably also need to modify the InputClaims
of the Userinfo configuration to map the returned properties names to the ones expected by the authorization service, in order for them to be saved correctly in the users collection.
To achieve this you have to add the PartnerClaimType
attribute with the correct name, as shown in the following example:
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<InputClaim ClaimTypeReferenceId="givenName"/>
<InputClaim ClaimTypeReferenceId="surname"/>
<InputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
</InputClaims>
Refer to this section of the AD B2C documentation for a thorough explanation on how to do it.
Furthermore, you must add the clientId
in the scope
array so that the access_token
is correctly returned, as explained in the documentation.
This is a configuration example for an app provider using Bitbucket Server authentication.
{
"apps": {
"web": {
"providers": {
"bitbucket": {
"type": "bitbucket",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "https://{KEYCLOAK_URL}/rest/oauth2/latest/authorize",
"tokenUrl": "https://{KEYCLOAK_URL}/rest/oauth2/latest/token",
"userInfoUrl": "https://{KEYCLOAK_URL}/plugins/servlet/applinks/whoami",
"baseUrl": "https://{KEYCLOAK_URL}/rest/oauth2/latest",
"scope": ["PUBLIC_REPOS"],
"order": 10,
"userSettingsURL": "https://{KEYCLOAK_URL}/profile/"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
This is a configuration example for an app using Keycloak provider.
{
"apps": {
"web": {
"providers": {
"keycloak": {
"type": "keycloak",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "https://{KEYCLOAK_URL}/auth/realms/my-realm/protocol/openid-connect/auth",
"tokenUrl": "https://{KEYCLOAK_URL}/auth/realms/my-realm/protocol/openid-connect/token",
"userInfoUrl": "https://{KEYCLOAK_URL}/auth/realms/my-realm/protocol/openid-connect/userinfo",
"baseUrl": "https://{KEYCLOAK_URL}/{tenantId}/auth/realms/my-realm/",
"scope": ["openid"],
"order": 10,
"userSettingsURL": "https://{KEYCLOAK_URL}/dashboard"
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
This is a configuration example for an app using the generic OAuth2 authentication provider.
{
"apps": {
"web": {
"providers": {
"generic": {
"type": "generic",
"clientId": "the-idp-client-id",
"clientSecret": "the-idp-client-secret",
"authUrl": "YOUR_AUTH_URL",
"tokenUrl": "YOUR_TOKEN_URL",
"userInfoUrl": "YOUR_USER_INFO_URL",
"baseUrl": "YOUR_BASE_URL",
"scope": ["YOUR", "SCOPES"],
"order": 10,
"userSettingsURL": "YOUR_USER_SETTINGS_URL",
"oidcKeys": {
"id": "YOUR_ID_KEY",
"name": "YOUR_NAME_KEY",
"username": "YOUR_USERNAME_KEY",
"email": "YOUR_EMAIL_KEY"
}
}
},
"redirectUrl": "https://test.com/callback",
"realm": "my-realm",
"issuer": "issuer1",
"defaultGroups": []
}
}
}
Redis storage
This feature is available from service tag 3.0.0
Redis is used to store some information regarding the user session. With the environment variable STORED_ACCESS_TOKEN_NUMBER it's possible to configure how many sessions can be stored and set a limit to the maximum number of concurrent active session.
The endpoint DELETE-/expired-sessions
can be used to clean all queues deleting the expired tokens.