Neo4j Single Sign-On (SSO) Configuration

This tutorial provides detailed examples of how to configure Single Sign-On (SSO) for several identity providers. It also presents frequently asked questions and solutions to common problems encountered when configuring SSO.

Neo4j supports SSO authentication and authorization through identity providers that implement the OpenID Connect standard.

Note that the following configurations are crafted for a Neo4j Browser served on http://localhost:7474/browser/ (the default URL when starting the database on localhost). The redirect URI http://localhost:7474/browser/?idp_id={{provider}}&auth_flow_step=redirect_uri should be modified when reproducing these examples in the identity providers substituting for the one serving the browser application.

SSO works in the following way:

  • The server (Neo4j database) contacts the identity provider (Okta, Azure, Google, etc) and fetches the JSON Web Keys (JWKs) from the provider.

  • The client (e.g. Bloom, Neo4j Browser etc.) asks the user for credentials and contacts the identity provider.

  • The identity provider responds with a JSON Web Token (JWT), a JSON containing fields (claims), relative to the user (email, audience, groups, etc).

  • The client provides the server the JWT and the server verifies its signature with the JWKs.

1. Okta

This example shows how to configure Okta for authentication and authorization using access tokens.

First, configure the client with the appropriate redirect URI. Group assignments can be skipped in this step:

oidc okta client creation
Figure 1. Okta OIDC client creation
oidc okta client config a
Figure 2. Okta OIDC client configuration

Note the client id and the domain (for the well known OpenIDC connect endpoint) will be used later in our Neo4j config:

oidc okta client config b
Figure 3. Okta OIDC client configuration

We will create groups in Okta, assign users to them (the user can be added to a group either on user creation or editing the group) and map them in the neo4j.conf to native groups:

oidc okta server groups
Figure 4. Okta OIDC server groups

Configure the default authorization server (the one that shows api://default as audience) to return the groups claim in access tokens:

oidc okta authz server
Figure 5. Okta OIDC authorization server
oidc okta server claims
Figure 6. Okta OIDC server claims

The neo4j.conf configuration used is:

dbms.security.authentication_providers=oidc-okta
dbms.security.authorization_providers=oidc-okta
dbms.security.oidc.okta.display_name=Okta
dbms.security.oidc.okta.auth_flow=pkce
dbms.security.oidc.okta.well_known_discovery_uri=https://dev-21056049.okta.com/oauth2/default/.well-known/openid-configuration
dbms.security.oidc.okta.audience=api://default
dbms.security.oidc.okta.claims.username=sub
dbms.security.oidc.okta.claims.groups=groups
dbms.security.oidc.okta.params=client_id=0oa3oq6uw3uSOBf8y5d7;response_type=code;scope=openid profile email
dbms.security.oidc.okta.authorization.group_to_role_mapping= "engineers" = admin; \
                                                             "collaborators" = reader

Note that the token_type_principal and the token_type_authentication were omitted, which means that access tokens are used instead.

You can now log in with Okta using the email of an engineer role user that results in an admin role in the database:

oidc okta successful login
Figure 7. Okta OIDC successful login

2. Azure Active Directory (AAD)

This example shows how to configure AAD for authentication and authorization using id tokens.

First, configure the client with the appropriate redirect URI:

oidc azure client creation
Figure 8. Azure OIDC client creation

Take note of the client id and the domain (for the well-known OpenIDC connect endpoint) as they are used later in your Neo4j config:

oidc azure client config
Figure 9. Azure OIDC client config

Create groups in the Azure AD console, assign users to them and map them in the neo4j.conf to native groups.

In this case the groups claim in the JWT will contain the id of the group, so we will need to map that id to the desired native role later on:

oidc azure server groups
Figure 10. Azure OIDC server groups

Configure the server to return the groups claim in identity tokens, modifying the Manifest of the registered application:

oidc azure server claims
Figure 11. Azure OIDC server claims

The neo4j.conf configuration used is:

dbms.security.authentication_providers=oidc-azure
dbms.security.authorization_providers=oidc-azure
dbms.security.oidc.azure.display_name=Azure
dbms.security.oidc.azure.auth_flow=pkce
dbms.security.oidc.azure.well_known_discovery_uri=https://login.microsoftonline.com/ce976899-299d-4a01-91e5-a5fee8f98626/v2.0/.well-known/openid-configuration
dbms.security.oidc.azure.audience=c2830ff5-86d9-4e38-8a2b-9efad6f3d06d
dbms.security.oidc.azure.claims.username=email
dbms.security.oidc.azure.claims.groups=groups
dbms.security.oidc.azure.params=client_id=c2830ff5-86d9-4e38-8a2b-9efad6f3d06d;response_type=code;scope=openid profile email
dbms.security.oidc.azure.config=token_type_principal=id_token;token_type_authentication=id_token
dbms.security.oidc.azure.authorization.group_to_role_mapping= "e8b6ddfa-688d-4ace-987d-6cc5516af188" = admin; \
                                                              "9e2a31e1-bdd1-47fe-844d-767502bd138d" = reader

You can now log in with Azure using the email of an engineer role user that results in an admin role in the database:

oidc azure successful login
Figure 12. Azure OIDC successful login

3. Google

This example shows how to use Google OpenIDC for authentication using id tokens in conjunction with native authorization.

Configuring the client and the redirect URI:

oidc google client creation
Figure 13. Google OIDC client creation
oidc google client config
Figure 14. Google OIDC client configuration

SSO authorization does not work with Google, since the JWT returned by Google does not contain information about the groups a user belongs to and cannot be configured to. It is recommended to use native (or another flavor) authorization by creating a native version of the user in Neo4j.

The role assigned to the email used to log in with SSO, in this case alice@neo4j-test.com, should have GRANT ROLE permissions in the database (native authentication temporarily enabled):

CREATE USER `alice@neo4j-test.com` SET PASSWORD 'pass';
GRANT ROLE admin to `alice@neo4j-test.com`;

The neo4j.conf configuration used is:

dbms.security.authentication_providers=oidc-google
dbms.security.authorization_providers=native
dbms.security.oidc.google.display_name=Google
dbms.security.oidc.google.auth_flow=pkce
dbms.security.oidc.google.well_known_discovery_uri=https://accounts.google.com/.well-known/openid-configuration
dbms.security.oidc.google.audience=345461137297-v9brpjmgbvbm3d5s9fq65tktevosd3rn.apps.googleusercontent.com
dbms.security.oidc.google.claims.username=email
dbms.security.oidc.google.params=client_id=345461137297-v9brpjmgbvbm3d5s9fq65tktevosd3rn.apps.googleusercontent.com;response_type=code;scope=openid profile email
dbms.security.oidc.google.token_params=client_secret=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
dbms.security.oidc.google.config=token_type_principal=id_token;token_type_authentication=id_token

You can now log in with Google using the email address and get the admin role when doing so:

oidc azure successful login
Figure 15. Azure OIDC successful login

Note that the native authentication is disabled, otherwise someone could log in to alice@neo4j-test.com natively with the set password.

4. FAQ

4.1. When should pkce be used as auth flow?

Assuming the client (in this case Neo4j Browser or Bloom) can be accessed through the public internet, always use pkce auth-flow rather than implicit. This is because the later one requires a client secret to be available to the public client.

In general, if both flows are available, it is recommended to opt for pkce given increased security with respect to implicit.

4.2. Is Google authentication secure if it has a client secret in the config listed above?

Yes. Google uses the pkce flow, but sometimes identity providers also use a client secret to ensure the client asking for a token is the one using it (pkce does not ensure that). The client secret does not add any additional security as it is public , but the pkce flow provides sufficient security.

4.3. Could not parse JWT of type "access_token"

When getting the message Failed to get credentials: Could not parse JWT of type "access_token" on Browser it probably means the provider only accepts id tokens.

oidc access token error
Figure 16. Failed to parse JWT of type access_token

Change to id tokens in your neo4j.conf:

dbms.security.oidc.{{provider}}.config=token_type_principal=id_token;token_type_authentication=id_token

4.4. When should identity tokens vs access tokens be used?

In general, it is safer to use access tokens when possible due to them being shorter-lived. That means if authorization permissions change on the identity provider, Neo4j would fail authorization and Browser would try to reconnect and reflect the changed permissions faster than if id tokens were used.

4.5. How to debug further problems with the configuration

Apart from the logs available at logs/debug.log and logs/security.log in the Neo4j path, the best way to debug this feature is to use a web-development console in your web browser when doing the SSO authentication flow with Bloom or Browser.

This could reveal potential problems as the one presented below with an example identity provider and the Cross-Origin Request policy:

oidc cors error
Figure 17. CORS error

The solution involves adding the redirect domain to the list of allowed domains in the provider (in this case localhost:8080):

oidc cors error solution
Figure 18. CORS error solution allowing the redirect domain on the provider