Skip to content

Commit 13d8c25

Browse files
Rotating authentication tokens (#444)
1 parent 8f971f2 commit 13d8c25

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed

go-manual/modules/ROOT/pages/connect-advanced.adoc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,43 @@ driver, err := neo4j.NewDriverWithContext(dbUri, neo4j.NoAuth())
6464
----
6565

6666

67+
[role=label--new-5.14]
68+
== Rotating authentication tokens
69+
70+
It is possible to rotate authentication tokens that are expected to expire (e.g. SSO).
71+
You need to provide a link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#TokenManager[`TokenManager`] instance when instantiating the `Driver`, rather than a static authentication token.
72+
73+
The easiest way to get started is to use one of built-in implementations: link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#BasicTokenManager[`BasicTokenManager`] and link:https://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v5/neo4j/auth#BearerTokenManager[`BearerTokenManager`].
74+
75+
.Rotating a bearer token expiring every 60 seconds
76+
[source, go, test-skip]
77+
----
78+
fetchAuthTokenFromProvider := func(ctx context.Context) (neo4j.AuthToken, *time.Time, error) {
79+
// some way of getting a token
80+
token, err := getSsoToken(ctx)
81+
if err != nil {
82+
return neo4j.AuthToken{}, nil, err
83+
}
84+
// assume we know tokens expire every 60 seconds
85+
expiresIn := time.Now().Add(60 * time.Second)
86+
// include a little buffer so that we fetch a new token before the old one expires
87+
expiresIn = expiresIn.Add(-10 * time.Second)
88+
// or return nil instead of `&expiresIn` if we don't expect it to expire
89+
return token, &expiresIn, nil
90+
}
91+
92+
// create a new driver with a bearer token manager
93+
_, _ = neo4j.NewDriverWithContext(dbUri, auth.BearerTokenManager(fetchAuthTokenFromProvider))
94+
----
95+
96+
[NOTE]
97+
This API must not be used for switching users. Auth managers must always return tokens for the same identity.
98+
You can switch users at both xref:query-simple.adoc#impersonation[query level] and xref:transactions.adoc#impersonation[session level].
99+
100+
[WARNING]
101+
`TokenManager` implementations and providers must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
102+
103+
67104
== Custom address resolver
68105

69106
When creating a `DriverWithContext` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.

java-manual/modules/ROOT/pages/connect-advanced.adoc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,52 @@ GraphDatabase.driver(dbUri, AuthTokens.custom(principal, credentials, realm, sch
7272
If authentication is disabled on the server, the authentication parameter can be omitted entirely.
7373

7474

75+
[role=label--new-5.18]
76+
== Rotating authentication tokens
77+
78+
It is possible to rotate authentication tokens that are expected to expire (e.g. SSO).
79+
You need to provide a link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/AuthTokenManager.html[`AuthTokenManager`] instance when instantiating the `Driver`, rather than a static authentication token.
80+
81+
The easiest way to get started is to use link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/AuthTokenManagers.html[one of built-in `AuthTokenManager` implementations]. AuthTokenManagers work with link:https://neo4j.com/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/AuthTokens.html[`AuthToken`] objects.
82+
83+
.Rotating a bearer token expiring every 60 seconds
84+
[source, java, test-skip]
85+
----
86+
// import java.time.Clock;
87+
// import java.util.concurrent.TimeUnit;
88+
// import org.neo4j.driver.AuthTokenManagers;
89+
// import org.neo4j.driver.AuthTokens;
90+
// import org.neo4j.driver.GraphDatabase;
91+
92+
void rotatingBearerDriver() {
93+
var tokenManager = AuthTokenManagers.bearer(() -> {
94+
var token = AuthTokens.bearer(getToken());
95+
96+
// Assume we know tokens expire every 60 seconds
97+
var expiresIn = TimeUnit.SECONDS.toMillis(60);
98+
// Include a little buffer so that new token is fetched before the old one expires
99+
var expiration = Clock.systemUTC().millis() + (expiresIn - TimeUnit.SECONDS.toMillis(10));
100+
101+
return token.expiringAt(expiration);
102+
});
103+
104+
var driver = GraphDatabase.driver(dbUri, tokenManager);
105+
}
106+
107+
// Some way to get a token
108+
private String getToken() {
109+
return "token-string";
110+
}
111+
----
112+
113+
[NOTE]
114+
This API must not be used for switching users. Auth managers must always return tokens for the same identity.
115+
You can switch users at both xref:query-simple.adoc#impersonation[query level] and xref:transactions.adoc#impersonation[session level].
116+
117+
[WARNING]
118+
`AuthTokenManager` objects must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
119+
120+
75121
== Logging
76122

77123
By default, the driver logs `INFO` messages through the Java logging framework `java.util.logging`.

javascript-manual/modules/ROOT/pages/connect-advanced.adoc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,61 @@ const driver = neo4j.driver(
6565
If authentication is disabled on the server, the authentication parameter can be omitted entirely.
6666

6767

68+
[role=label--new-5.14]
69+
== Rotating authentication tokens
70+
71+
It is possible to rotate authentication tokens that are expected to expire (e.g. SSO).
72+
You need to provide a link:https://neo4j.com/docs/api/javascript-driver/current/class/lib6/auth-token-manager.js~AuthTokenManager.html[`AuthTokenManager`] instance when instantiating the `Driver`, rather than a static authentication token.
73+
74+
The easiest way to get started is to use link:https://neo4j.com/docs/api/javascript-driver/current/class/lib6/auth-token-manager.js~AuthTokenManagers.html[one of built-in `AuthTokenManager` implementations].
75+
76+
.Rotating a bearer token expiring every 60 seconds
77+
[source, javascript, test-skip]
78+
----
79+
import neo4j, { AuthToken } from 'neo4j-driver'
80+
81+
/**
82+
* Method called whenever the driver needs to refresh the token.
83+
*
84+
* The refresh will happen if the driver is notified by the server
85+
* of token expiration, or if `Date.now() > tokenData.expiry`.
86+
*
87+
* The driver will block creation of all connections until
88+
* this function resolves the new auth token.
89+
*/
90+
async function generateAuthToken () {
91+
const bearer = await getSSOToken() // some way to get a token
92+
const token = neo4j.auth.bearer(bearer)
93+
94+
// assume we know tokens expire every 60 seconds
95+
const expiresIn = 60
96+
// Include a little buffer so that new token is fetched before the old one expires
97+
const expiration = expiresIn - 10
98+
99+
return {
100+
token,
101+
// if expiration is not provided,
102+
// the driver will only fetch a new token when an auth failure happens
103+
expiration
104+
}
105+
}
106+
107+
const driver = neo4j.driver(
108+
URI,
109+
neo4j.authTokenManagers.bearer({
110+
tokenProvider: generateAuthToken
111+
})
112+
)
113+
----
114+
115+
[NOTE]
116+
This API must not be used for switching users. Auth managers must always return tokens for the same identity.
117+
You can switch users at both xref:query-simple.adoc#impersonation[query level] and xref:transactions.adoc#impersonation[session level].
118+
119+
[WARNING]
120+
`AuthManagers` (including provider functions passed to `expirationBasedAuthTokenManager()`) must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
121+
122+
68123
== Custom address resolver
69124

70125
When creating a `Driver` object, you can specify a _resolver_ function to resolve the connection address the driver is initialized with.

python-manual/modules/ROOT/pages/connect-advanced.adoc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,50 @@ Use the function link:{neo4j-docs-base-uri}/api/python-driver/current/api.html#n
6363
If authentication is disabled on the server, the authentication parameter can be omitted entirely.
6464

6565

66+
[role=label--new-5.14]
67+
== Rotating authentication tokens
68+
69+
It is possible to rotate authentication tokens that are expected to expire (e.g. SSO).
70+
You need to provide a link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.AuthManager[`AuthManager`] instance (or link:https://neo4j.com/docs/api/python-driver/current/async_api.html#neo4j.auth_management.AsyncAuthManager[`AsyncAuthManager`] for the async driver) when instantiating the `Driver`, rather than a static authentication token.
71+
72+
The easiest way to get started is to use link:https://neo4j.com/docs/api/python-driver/current/api.html#neo4j.auth_management.AuthManagers[one of built-in `AuthManager` implementations].
73+
74+
.Rotating a bearer token expiring every 60 seconds
75+
[source, python, test-skip]
76+
----
77+
import neo4j
78+
from neo4j.auth_management import (
79+
AuthManagers,
80+
ExpiringAuth,
81+
)
82+
83+
84+
def auth_provider():
85+
# Some way to get a token
86+
sso_token = get_sso_token()
87+
# Assume we know tokens expire every 60 seconds
88+
expires_in = 60
89+
# Include a little buffer so that new token is fetched before the old one expires
90+
expires_in -= 10
91+
92+
auth = neo4j.bearer_auth(sso_token)
93+
return ExpiringAuth(auth=auth).expires_in(expires_in)
94+
95+
with neo4j.GraphDatabase.driver(
96+
URI,
97+
auth=AuthManagers.expiration_based(auth_provider)
98+
) as driver:
99+
...
100+
----
101+
102+
[NOTE]
103+
This API must not be used for switching users. Auth managers must always return tokens for the same identity.
104+
You can switch users at both xref:query-simple.adoc#impersonation[query level] and xref:transactions.adoc#impersonation[session level].
105+
106+
[WARNING]
107+
`AuthManagers` (including provider functions passed to `AuthManagers.expiration_based()`) must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.
108+
109+
66110
== Custom address resolver
67111

68112
When creating a `Driver` object, you can specify a _resolver_ function to resolve any addresses the driver receives ahead of DNS resolution.

0 commit comments

Comments
 (0)