@@ -72,17 +72,18 @@ private static void checkFeatureSyncServerAvailable() {
7272 * Use {@link Sync#server(BoxStore, String, SyncCredentials)} instead.
7373 */
7474 @ Internal
75- public SyncServerBuilder (BoxStore boxStore , String url , @ Nullable SyncCredentials authenticatorCredentials ) {
75+ public SyncServerBuilder (BoxStore boxStore , String url , SyncCredentials authenticatorCredentials ) {
7676 checkNotNull (boxStore , "BoxStore is required." );
7777 checkNotNull (url , "Sync server URL is required." );
78+ checkNotNull (authenticatorCredentials , "Authenticator credentials are required." );
7879 checkFeatureSyncServerAvailable ();
7980 this .boxStore = boxStore ;
8081 try {
8182 this .url = new URI (url );
8283 } catch (URISyntaxException e ) {
8384 throw new IllegalArgumentException ("Sync server URL is invalid: " + url , e );
8485 }
85- authenticatorCredentialsOrNull (authenticatorCredentials );
86+ authenticatorCredentials (authenticatorCredentials );
8687 }
8788
8889 /**
@@ -100,7 +101,9 @@ public SyncServerBuilder(BoxStore boxStore, String url, SyncCredentials[] multip
100101 } catch (URISyntaxException e ) {
101102 throw new IllegalArgumentException ("Sync server URL is invalid: " + url , e );
102103 }
103- authenticatorCredentials (multipleAuthenticatorCredentials );
104+ for (SyncCredentials credentials : multipleAuthenticatorCredentials ) {
105+ authenticatorCredentials (credentials );
106+ }
104107 }
105108
106109 /**
@@ -115,48 +118,39 @@ public SyncServerBuilder certificatePath(String certificatePath) {
115118 return this ;
116119 }
117120
118- private SyncServerBuilder authenticatorCredentialsOrNull (@ Nullable SyncCredentials authenticatorCredentials ) {
119- if (authenticatorCredentials == null ) {
120- return this ; // Do nothing
121- }
122- if (!(authenticatorCredentials instanceof SyncCredentialsToken )) {
123- throw new IllegalArgumentException ("Sync credentials of type " + authenticatorCredentials .getType ()
124- + " are not supported" );
125- }
126- credentials .add ((SyncCredentialsToken ) authenticatorCredentials );
127- return this ;
128- }
129-
130121 /**
131122 * Adds additional authenticator credentials to authenticate clients or peers with.
132123 * <p>
133- * For the embedded server, currently only {@link SyncCredentials#sharedSecret} and {@link SyncCredentials#none}
134- * are supported.
124+ * For the embedded server, currently only {@link SyncCredentials#sharedSecret}, any JWT method like
125+ * {@link SyncCredentials#jwtIdTokenServer()} as well as {@link SyncCredentials#none} are supported.
135126 */
136127 public SyncServerBuilder authenticatorCredentials (SyncCredentials authenticatorCredentials ) {
137128 checkNotNull (authenticatorCredentials , "Authenticator credentials must not be null." );
138- return authenticatorCredentialsOrNull (authenticatorCredentials );
139- }
140-
141- /**
142- * Adds additional authenticator credentials to authenticate clients or peers with.
143- * <p>
144- * For the embedded server, currently only {@link SyncCredentials#sharedSecret} and {@link SyncCredentials#none}
145- * are supported.
146- */
147- public SyncServerBuilder authenticatorCredentials (SyncCredentials [] multipleAuthenticatorCredentials ) {
148- checkNotNull (multipleAuthenticatorCredentials , "Authenticator credentials must not be null." );
149- for (SyncCredentials credentials : multipleAuthenticatorCredentials ) {
150- authenticatorCredentials (credentials );
129+ if (!(authenticatorCredentials instanceof SyncCredentialsToken )) {
130+ throw new IllegalArgumentException ("Sync credentials of type " + authenticatorCredentials .getType ()
131+ + " are not supported" );
151132 }
133+ SyncCredentialsToken tokenCredential = (SyncCredentialsToken ) authenticatorCredentials ;
134+ SyncCredentials .CredentialsType type = tokenCredential .getType ();
135+ switch (type ) {
136+ case JWT_ID_TOKEN :
137+ case JWT_ACCESS_TOKEN :
138+ case JWT_REFRESH_TOKEN :
139+ case JWT_CUSTOM_TOKEN :
140+ if (tokenCredential .hasToken ()) {
141+ throw new IllegalArgumentException ("Must not supply a token for a credential of type "
142+ + authenticatorCredentials .getType ());
143+ }
144+ }
145+ credentials .add (tokenCredential );
152146 return this ;
153147 }
154148
155149 /**
156150 * Sets a listener to observe fine granular changes happening during sync.
157151 * <p>
158- * This listener can also be {@link SyncServer#setSyncChangeListener(SyncChangeListener) set or removed}
159- * on the Sync server directly.
152+ * This listener can also be {@link SyncServer#setSyncChangeListener(SyncChangeListener) set or removed} on the Sync
153+ * server directly.
160154 */
161155 public SyncServerBuilder changeListener (SyncChangeListener changeListener ) {
162156 this .changeListener = changeListener ;
@@ -282,6 +276,10 @@ public SyncServerBuilder workerThreads(int workerThreads) {
282276 * Sets the public key used to verify JWT tokens.
283277 * <p>
284278 * The public key should be in the PEM format.
279+ * <p>
280+ * However, typically the key is supplied using a JWKS file served from a {@link #jwtPublicKeyUrl(String)}.
281+ * <p>
282+ * See {@link #jwtPublicKeyUrl(String)} for a common configuration to enable JWT auth.
285283 */
286284 public SyncServerBuilder jwtPublicKey (String publicKey ) {
287285 this .jwtPublicKey = publicKey ;
@@ -290,6 +288,19 @@ public SyncServerBuilder jwtPublicKey(String publicKey) {
290288
291289 /**
292290 * Sets the JWKS (Json Web Key Sets) URL to fetch the current public key used to verify JWT tokens.
291+ * <p>
292+ * A working JWT configuration can look like this:
293+ * <pre>{@code
294+ * SyncCredentials auth = SyncCredentials.jwtIdTokenServer();
295+ * SyncServer server = Sync.server(store, url, auth)
296+ * .jwtPublicKeyUrl("https://example.com/public-key")
297+ * .jwtClaimAud("<audience>")
298+ * .jwtClaimIss("<issuer>")
299+ * .build();
300+ * }</pre>
301+ *
302+ * See the <a href="https://sync.objectbox.io/sync-server-configuration/jwt-authentication">JWT authentication documentation</a>
303+ * for details.
293304 */
294305 public SyncServerBuilder jwtPublicKeyUrl (String publicKeyUrl ) {
295306 this .jwtPublicKeyUrl = publicKeyUrl ;
@@ -298,6 +309,8 @@ public SyncServerBuilder jwtPublicKeyUrl(String publicKeyUrl) {
298309
299310 /**
300311 * Sets the JWT claim "iss" (issuer) used to verify JWT tokens.
312+ *
313+ * @see #jwtPublicKeyUrl(String)
301314 */
302315 public SyncServerBuilder jwtClaimIss (String claimIss ) {
303316 this .jwtClaimIss = claimIss ;
@@ -306,6 +319,8 @@ public SyncServerBuilder jwtClaimIss(String claimIss) {
306319
307320 /**
308321 * Sets the JWT claim "aud" (audience) used to verify JWT tokens.
322+ *
323+ * @see #jwtPublicKeyUrl(String)
309324 */
310325 public SyncServerBuilder jwtClaimAud (String claimAud ) {
311326 this .jwtClaimAud = claimAud ;
@@ -322,7 +337,8 @@ private boolean hasJwtConfig() {
322337 * Note: this clears all previously set authenticator credentials.
323338 */
324339 public SyncServer build () {
325- if (!hasJwtConfig () && credentials .isEmpty ()) {
340+ // Note: even when only using JWT auth, must supply one of the credentials of JWT type
341+ if (credentials .isEmpty ()) {
326342 throw new IllegalStateException ("At least one authenticator is required." );
327343 }
328344 if (hasJwtConfig ()) {
@@ -374,10 +390,7 @@ byte[] buildSyncServerOptions() {
374390 if (clusterId != null ) {
375391 clusterIdOffset = fbb .createString (clusterId );
376392 }
377- int authenticationMethodsOffset = 0 ;
378- if (!credentials .isEmpty ()) {
379- authenticationMethodsOffset = buildAuthenticationMethods (fbb );
380- }
393+ int authenticationMethodsOffset = buildAuthenticationMethods (fbb );
381394 int clusterPeersVectorOffset = buildClusterPeers (fbb );
382395 int jwtConfigOffset = 0 ;
383396 if (hasJwtConfig ()) {
@@ -396,9 +409,7 @@ byte[] buildSyncServerOptions() {
396409 // After collecting all offsets, create options
397410 SyncServerOptions .startSyncServerOptions (fbb );
398411 SyncServerOptions .addUrl (fbb , urlOffset );
399- if (authenticationMethodsOffset != 0 ) {
400- SyncServerOptions .addAuthenticationMethods (fbb , authenticationMethodsOffset );
401- }
412+ SyncServerOptions .addAuthenticationMethods (fbb , authenticationMethodsOffset );
402413 if (syncFlags != 0 ) {
403414 SyncServerOptions .addSyncFlags (fbb , syncFlags );
404415 }
0 commit comments