Skip to content

Instantly share code, notes, and snippets.

@Exerosis
Created August 1, 2018 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Exerosis/a82b31a7a9cbc88e2761fa84c3ada5e9 to your computer and use it in GitHub Desktop.
Save Exerosis/a82b31a7a9cbc88e2761fa84c3ada5e9 to your computer and use it in GitHub Desktop.
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import static java.lang.Integer.parseInt;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.net.URLEncoder.encode;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.concurrent.TimeUnit.SECONDS;
import static spark.Spark.*;
public class GoogleAuthenticator {
private static final String FORMAT_AUTH_REQUEST = "https://accounts.google.com/o/oauth2/v2/auth" +
"?redirect_uri=%s" +
"&client_id=%s" +
"&login_hint=%s" +
"&prompt=%s" +
"&state=%s" +
"&scope=%s";
private static final String
PARAM_STATE = "state",
PARAM_ACCESS_TOKEN = "access_token",
PARAM_EXPIRES_IN = "expires_in";
private final Map<String, Consumer<Optional<Token>>> listeners = new HashMap<>();
private final String redirectUrl;
public GoogleAuthenticator(String redirectUrl) throws IOException {
this(new URL(redirectUrl));
}
public GoogleAuthenticator(URL redirectUrl) throws UnsupportedEncodingException {
this.redirectUrl = encode(redirectUrl.toString(), UTF_8.name());
init();
port(redirectUrl.getPort());
ipAddress(redirectUrl.getHost());
get(redirectUrl.getPath(), (request, response) -> {
final String state = request.queryParams(PARAM_STATE);
if (state == null)
throw new IllegalStateException("No state was returned!");
final String token = request.queryParams(PARAM_ACCESS_TOKEN);
final Consumer<Optional<Token>> listener = listeners.remove(state);
if (listener != null)
listener.accept(token == null ? empty() : of(new Token(
token,
parseInt(request.queryParams(PARAM_EXPIRES_IN))
)));
return response;
});
}
public URL authenticate(
Object clientId,
String state,
String scope,
String hint,
Prompt prompt,
Consumer<Optional<Token>> callback
) {
try {
listeners.put(state, callback);
return new URL(format(
FORMAT_AUTH_REQUEST,
redirectUrl,
clientId,
hint,
prompt,
state,
scope
));
} catch (MalformedURLException reason) {
throw new RuntimeException(reason);
}
}
public enum Prompt {
NONE, CONSENT, SELECT_ACCOUNT;
private final String name = name().toLowerCase();
@Override
public String toString() { return name; }
}
public static class Token {
public final String token;
public final long expiration;
Token(String token, int expiresIn) {
this.token = token;
this.expiration = currentTimeMillis() + SECONDS.toMillis(expiresIn);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment