Skip to content

Commit 16ddf41

Browse files
Merge branch 'main' into patch-1
2 parents cf7134b + c2be37e commit 16ddf41

18 files changed

Lines changed: 1527 additions & 87 deletions

AGENTS.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# AI coding assistant guidelines: Firebase Admin Java SDK
2+
3+
This document defines repository-wide expectations, code styles, and Checkstyle compliance metrics that every autonomous AI coding agent or pair programming assistant must strictly follow when introducing or modifying code in this repository.
4+
5+
---
6+
7+
## 🎨 Code Style & Checkstyle Compliance
8+
9+
This repository enforces standard **Google Java Style** guidelines validated through automated Maven checkstyle executions (`checkstyle.xml`). Any compilation or pull request build will fail if these constraints are violated.
10+
11+
### 1. Strict 100-Character Line Limit
12+
* **Rule:** No line of code, comments, Javadoc documentation entries, or inline string literal concatenations may exceed **100 characters** under any circumstances.
13+
* **Remediation:**
14+
* Break long method parameters, array initializations, and logic comparisons onto separate lines.
15+
* Wrap long `assertThrows` statements or lambda chains across multiple contiguous lines.
16+
* Format long log messages, exception messages, or assertion string explanations using standard string block concatenation broken across separate lines.
17+
18+
### 2. Import Ordering & Grouping
19+
* **Rule:** Imports must be grouped and arranged alphabetically to avoid validation noise.
20+
* **Remediation:**
21+
1. Static imports placed first, grouped, and alphabetically arranged.
22+
2. Non-static imports grouped alphabetically by package tier.
23+
3. Avoid utilizing wildcard (`*`) imports. Every import declaration must be explicit.
24+
25+
### 3. Javadoc Completeness & Formatting
26+
* **Rule:** Every public class, package-private component interface, constructor, and public method signature must include fully formed Javadoc documentation blocks.
27+
* **Remediation:**
28+
* Document all arguments via `@param`, explain error flows via `@throws`, and clear return constraints via `@return`.
29+
* Wrap documentation description text explicitly so that no single javadoc documentation line passes the 100 characters limit.
30+
31+
### 4. Indentation & Spacing
32+
* **Rule:** Standard indentation uses exactly **2 spaces** per block indentation level. **4 spaces** are used explicitly for wrapped line continuation indentation.
33+
* **Remediation:** Never utilize tab characters. Ensure block braces follow the Google K&R opening line placement convention.

pom.xml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
<groupId>com.google.firebase</groupId>
2121
<artifactId>firebase-admin</artifactId>
22-
<version>9.8.0</version>
22+
<version>9.9.0</version>
2323
<packaging>jar</packaging>
2424

2525
<name>firebase-admin</name>
@@ -59,7 +59,7 @@
5959
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
6060
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
6161
<skipUTs>${skipTests}</skipUTs>
62-
<netty.version>4.2.10.Final</netty.version>
62+
<netty.version>4.2.14.Final</netty.version>
6363
</properties>
6464

6565
<scm>
@@ -273,7 +273,7 @@
273273
<!-- Test Phase -->
274274
<plugin>
275275
<artifactId>maven-surefire-plugin</artifactId>
276-
<version>3.5.4</version>
276+
<version>3.5.5</version>
277277
<configuration>
278278
<skipTests>${skipUTs}</skipTests>
279279
</configuration>
@@ -330,7 +330,7 @@
330330
<!-- Verify Phase -->
331331
<plugin>
332332
<artifactId>maven-failsafe-plugin</artifactId>
333-
<version>3.5.4</version>
333+
<version>3.5.5</version>
334334
<executions>
335335
<execution>
336336
<goals>
@@ -378,7 +378,7 @@
378378
<dependency>
379379
<groupId>com.google.cloud</groupId>
380380
<artifactId>libraries-bom</artifactId>
381-
<version>26.76.0</version>
381+
<version>26.83.0</version>
382382
<type>pom</type>
383383
<scope>import</scope>
384384
</dependency>
@@ -424,7 +424,7 @@
424424
<dependency>
425425
<groupId>org.slf4j</groupId>
426426
<artifactId>slf4j-api</artifactId>
427-
<version>2.0.17</version>
427+
<version>2.0.18</version>
428428
</dependency>
429429
<dependency>
430430
<groupId>io.netty</groupId>
@@ -446,6 +446,11 @@
446446
<artifactId>httpclient5</artifactId>
447447
<version>5.3.1</version>
448448
</dependency>
449+
<dependency>
450+
<groupId>com.nimbusds</groupId>
451+
<artifactId>nimbus-jose-jwt</artifactId>
452+
<version>10.9</version>
453+
</dependency>
449454

450455
<!-- Test Dependencies -->
451456
<dependency>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.phonenumberverification;
18+
19+
import com.google.firebase.FirebaseApp;
20+
import com.google.firebase.ImplFirebaseTrampolines;
21+
import com.google.firebase.internal.FirebaseService;
22+
import com.google.firebase.phonenumberverification.internal.FirebasePhoneNumberVerificationTokenVerifier;
23+
24+
/**
25+
* This class is the entry point for the Firebase Phone Number Verification service.
26+
*
27+
* <p>You can get an instance of {@link FirebasePhoneNumberVerification} via {@link #getInstance()},
28+
* or {@link #getInstance(FirebaseApp)}.
29+
*/
30+
public final class FirebasePhoneNumberVerification {
31+
private static final String SERVICE_ID = FirebasePhoneNumberVerification.class.getName();
32+
private final FirebasePhoneNumberVerificationTokenVerifier tokenVerifier;
33+
34+
private FirebasePhoneNumberVerification(FirebaseApp app) {
35+
this.tokenVerifier = new FirebasePhoneNumberVerificationTokenVerifier(app);
36+
}
37+
38+
/**
39+
* Gets the {@link FirebasePhoneNumberVerification} instance for the default {@link FirebaseApp}.
40+
*
41+
* @return The {@link FirebasePhoneNumberVerification} instance for the default
42+
* {@link FirebaseApp}.
43+
*/
44+
public static FirebasePhoneNumberVerification getInstance() {
45+
return getInstance(FirebaseApp.getInstance());
46+
}
47+
48+
/**
49+
* Gets the {@link FirebasePhoneNumberVerification} instance for the specified
50+
* {@link FirebaseApp}.
51+
*
52+
* @return The {@link FirebasePhoneNumberVerification} instance for the specified
53+
* {@link FirebaseApp}.
54+
*/
55+
public static synchronized FirebasePhoneNumberVerification getInstance(FirebaseApp app) {
56+
FirebasePhoneNumberVerificationService service =
57+
ImplFirebaseTrampolines.getService(app, SERVICE_ID,
58+
FirebasePhoneNumberVerificationService.class);
59+
if (service == null) {
60+
service = ImplFirebaseTrampolines.addService(
61+
app, new FirebasePhoneNumberVerificationService(app));
62+
}
63+
return service.getInstance();
64+
}
65+
66+
/**
67+
* Verifies a Firebase Phone Number Verification token (JWT).
68+
*
69+
* @param phoneNumberVerificationJwt The JWT string to verify.
70+
* @return A verified {@link FirebasePhoneNumberVerificationToken}.
71+
* @throws FirebasePhoneNumberVerificationException If verification fails.
72+
*/
73+
public FirebasePhoneNumberVerificationToken verifyToken(String phoneNumberVerificationJwt)
74+
throws FirebasePhoneNumberVerificationException {
75+
return this.tokenVerifier.verifyToken(phoneNumberVerificationJwt);
76+
}
77+
78+
private static class FirebasePhoneNumberVerificationService
79+
extends FirebaseService<FirebasePhoneNumberVerification> {
80+
FirebasePhoneNumberVerificationService(FirebaseApp app) {
81+
super(SERVICE_ID, new FirebasePhoneNumberVerification(app));
82+
}
83+
}
84+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.phonenumberverification;
18+
19+
/**
20+
* Error codes that can be raised by the Phone Number Verification APIs.
21+
*/
22+
public enum FirebasePhoneNumberVerificationErrorCode {
23+
24+
/**
25+
* One or more arguments specified in the request were invalid.
26+
*/
27+
INVALID_ARGUMENT,
28+
29+
/**
30+
* The provided phone number verification token is invalid or malformed.
31+
*/
32+
INVALID_TOKEN,
33+
34+
/**
35+
* The provided phone number verification token has expired.
36+
*/
37+
TOKEN_EXPIRED,
38+
39+
/**
40+
* Internal error encountered during phone number verification.
41+
*/
42+
INTERNAL_ERROR,
43+
44+
/**
45+
* Phone number verification service is temporarily unavailable.
46+
*/
47+
SERVICE_ERROR,
48+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.phonenumberverification;
18+
19+
import com.google.firebase.ErrorCode;
20+
import com.google.firebase.FirebaseException;
21+
import com.google.firebase.IncomingHttpResponse;
22+
import com.google.firebase.internal.NonNull;
23+
import com.google.firebase.internal.Nullable;
24+
25+
/**
26+
* Generic exception related to Firebase Phone Number Verification. Check the error code and message
27+
* for more details.
28+
*/
29+
public class FirebasePhoneNumberVerificationException extends FirebaseException {
30+
31+
private final FirebasePhoneNumberVerificationErrorCode errorCode;
32+
33+
public FirebasePhoneNumberVerificationException(
34+
@NonNull ErrorCode errorCode,
35+
@NonNull String message,
36+
Throwable cause,
37+
IncomingHttpResponse response,
38+
FirebasePhoneNumberVerificationErrorCode phoneErrorCode) {
39+
super(errorCode, message, cause, response);
40+
this.errorCode = phoneErrorCode;
41+
}
42+
43+
public FirebasePhoneNumberVerificationException(FirebaseException base) {
44+
this(base.getErrorCode(), base.getMessage(), base.getCause(), base.getHttpResponse(), null);
45+
}
46+
47+
@Nullable
48+
public FirebasePhoneNumberVerificationErrorCode getPhoneNumberVerificationErrorCode() {
49+
return errorCode;
50+
}
51+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.phonenumberverification;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
import static com.google.common.base.Preconditions.checkNotNull;
21+
22+
import com.google.common.collect.ImmutableList;
23+
import com.google.common.collect.ImmutableMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
/**
28+
* Represents a verified Firebase Phone Number Verification token.
29+
*/
30+
public class FirebasePhoneNumberVerificationToken {
31+
private final Map<String, Object> claims;
32+
33+
/**
34+
* Create an instance of {@link FirebasePhoneNumberVerificationToken} from a map of JWT claims.
35+
*
36+
* @param claims A map of JWT claims.
37+
*/
38+
public FirebasePhoneNumberVerificationToken(Map<String, Object> claims) {
39+
checkNotNull(claims, "Claims map must not be null");
40+
checkArgument(claims.containsKey("sub"), "Claims map must contain sub");
41+
this.claims = ImmutableMap.copyOf(claims);
42+
}
43+
44+
/**
45+
* Returns the issuer identifier for the issuer of the response.
46+
*/
47+
public String getIssuer() {
48+
return (String) claims.get("iss");
49+
}
50+
51+
/**
52+
* Returns the phone number of the user.
53+
* This corresponds to the 'sub' claim in the JWT.
54+
*/
55+
public String getPhoneNumber() {
56+
return (String) claims.get("sub");
57+
}
58+
59+
/**
60+
* Returns the audience for which this token is intended.
61+
*/
62+
public List<String> getAudience() {
63+
Object audience = claims.get("aud");
64+
if (audience instanceof String) {
65+
return ImmutableList.of((String) audience);
66+
} else if (audience instanceof List) {
67+
@SuppressWarnings("unchecked")
68+
List<String> audienceList = (List<String>) audience;
69+
return ImmutableList.copyOf(audienceList);
70+
}
71+
return ImmutableList.of();
72+
}
73+
74+
/**
75+
* Returns the expiration time in seconds since the Unix epoch.
76+
*/
77+
public long getExpirationTime() {
78+
Object exp = claims.get("exp");
79+
if (exp instanceof java.util.Date) {
80+
return ((java.util.Date) exp).getTime() / 1000L;
81+
}
82+
return exp instanceof Number ? ((Number) exp).longValue() : 0L;
83+
}
84+
85+
/**
86+
* Returns the issued-at time in seconds since the Unix epoch.
87+
*/
88+
public long getIssuedAt() {
89+
Object iat = claims.get("iat");
90+
if (iat instanceof java.util.Date) {
91+
return ((java.util.Date) iat).getTime() / 1000L;
92+
}
93+
return iat instanceof Number ? ((Number) iat).longValue() : 0L;
94+
}
95+
96+
/**
97+
* Returns the entire map of claims.
98+
*/
99+
public Map<String, Object> getClaims() {
100+
return claims;
101+
}
102+
}

0 commit comments

Comments
 (0)