Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kalyandechiraju/0bd9a43a5aebd1b647e942db2cf1009a to your computer and use it in GitHub Desktop.
Save kalyandechiraju/0bd9a43a5aebd1b647e942db2cf1009a to your computer and use it in GitHub Desktop.
Firebase 3.0 + GAE
public class AppengineFirebaseAuth {
private static final String APP_ID = "YOUR_APP_ID";
public static AppengineFirebaseToken verifyIdToken(String token) {
Map<String, String> publicKeys = GooglePublicKeys.getKeys();
for (String kid : publicKeys.keySet()) {
String publicKey = publicKeys.get(kid);
try {
Jws<Claims> claimsJws = verifyIdTokey(token, kid, publicKey);
return new AppengineFirebaseToken(claimsJws.getBody());
} catch (SignatureException e) {
continue; // try next key
} catch (ExpiredJwtException e) {
throw new InvalidFirebaseTokenException(e.getMessage());
}
}
throw new InvalidFirebaseTokenException("No Google public keys for JWT Token");
}
private static Jws<Claims> verifyIdTokey(String token, String kid, String publicKey) {
PublicKey pk = createPk(publicKey);
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(pk).parseClaimsJws(token);
validate(claimsJws, kid);
return claimsJws;
}
private static void validate(Jws<Claims> claimsJws, String kid) {
if (claimsJws.getHeader().getAlgorithm().equals("RS256") &&
claimsJws.getBody().getAudience().equals(APP_ID) &&
claimsJws.getBody().getIssuer().equals("https://securetoken.google.com/" + APP_ID) &&
claimsJws.getBody().getSubject() != null &&
claimsJws.getHeader().getKeyId().equals(kid)) {
return;
}
throw new InvalidFirebaseTokenException("Invalid Firebase Id Token");
}
private static PublicKey createPk(String publicKey) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream stream = new ByteArrayInputStream(publicKey.getBytes("UTF-8"));
java.security.cert.Certificate cert = cf.generateCertificate(stream);
return cert.getPublicKey();
} catch (CertificateException | UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
public class AppengineFirebaseToken {
private Claims claims;
private String uid;
private String issuer;
private String name;
private String picture;
private String email;
private String emailVerified;
public AppengineFirebaseToken(Claims claims) {
this.claims = claims;
}
public String getUid() {
return (String) claims.get("user_id");
}
public String getIssuer() {
return (String) claims.get("iss");
}
public String getName() {
return (String) claims.get("name");
}
public String getPicture() {
return (String) claims.get("picture");
}
public String getEmail() {
return (String) claims.get("email");
}
public boolean isEmailVerified() {
return Boolean.valueOf((String) claims.get("email_verified"));
}
}
public class GooglePublicKeys {
private static final String GOOGLE_PUBLIC_KEYS = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com";
private static final int ONE_DAY = 1000 * 60 * 60 * 24;
private static GooglePublicKeys instance;
private long timestamp;
private Map<String, String> keys;
private GooglePublicKeys() {
}
public static Map<String, String> getKeys() {
if (instance == null || isOutdated()) {
reload();
}
return instance.keys;
}
private static boolean isOutdated() {
return instance.timestamp < System.currentTimeMillis() - ONE_DAY;
}
private synchronized static void reload() {
if (instance != null && !isOutdated()) {
return;
}
instance = new GooglePublicKeys();
instance.keys = fetchGooglePublicKeys();
instance.timestamp = System.currentTimeMillis();
}
private static Map<String, String> fetchGooglePublicKeys() {
return parseJson(fetchKeysJson());
}
private static String fetchKeysJson() {
try {
URLFetchService urlFetch = URLFetchServiceFactory.getURLFetchService();
HTTPResponse response = urlFetch.fetch(new URL(GOOGLE_PUBLIC_KEYS));
return new String(response.getContent());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static Map<String, String> parseJson(String json) {
Gson gson = new Gson();
Map<String, String> map = new HashMap<>();
return gson.fromJson(json, map.getClass());
}
}
public class InvalidFirebaseTokenException extends RuntimeException {
public InvalidFirebaseTokenException(String message) {
super(message);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment