Skip to content

Instantly share code, notes, and snippets.

@driversti
Created December 13, 2021 06:13
Show Gist options
  • Save driversti/dcd703dd203cc3c01e83f5531f000299 to your computer and use it in GitHub Desktop.
Save driversti/dcd703dd203cc3c01e83f5531f000299 to your computer and use it in GitHub Desktop.
OAuth 1.0a Twitter API example
import static java.lang.String.format
import static java.net.http.HttpRequest.BodyPublishers
import static java.net.http.HttpResponse.BodyHandlers
import com.github.driversti.twittygram.utils.PercentUtil
import com.github.driversti.twittygram.utils.SignatureUtil
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.time.Instant
import org.apache.commons.lang3.RandomStringUtils
class ListsRealTest extends RealUnitTest {
protected static final String MY_ID = "79765753"
protected static final API_URL = "https://api.twitter.com"
private static final OWNED_LISTS_URL = "$API_URL/2/users/%s/owned_lists"
def "should return lists owned by the given user with optional query parameters"() {
given:
def url = format(OWNED_LISTS_URL, MY_ID)
def urlParams = Map.of("expansions", "owner_id", "list.fields", "follower_count,member_count", "user.fields", "created_at")
def header = createOauthHeader("GET", url, urlParams)
// def header = "Bearer $BEARER_TOKEN"
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(new URI(url + "?expansions=owner_id&list.fields=follower_count,member_count&user.fields=created_at"))
.header("Content-Type", "application/json")
.header("Authorization", header)
.build()
println request
when:
HttpResponse<String> response = client.send(request, BodyHandlers.ofString())
then:
response.statusCode() == 200
def body = response.body()
println body
body.contains("IT related")
}
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class PercentUtil {
private static final String ASCII = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~";
private static final HexFormat HEX = HexFormat.of().withUpperCase();
public static String encode(final String source) {
Objects.requireNonNull(source, "The 'source' string should not be null!");
final StringBuilder builder = new StringBuilder();
for (byte b : source.getBytes(StandardCharsets.UTF_8)) {
final String currentCharacter = new String(new byte[]{b}, StandardCharsets.US_ASCII);
if (ASCII.contains(currentCharacter)) {
builder.append(currentCharacter);
} else {
builder.append("%").append(HEX.formatHex(new byte[]{b}));
}
}
return builder.toString();
}
public static String encode(final Map<String, String> parameters) {
final Map<String, String> encoded = parameters.entrySet().stream()
.collect(Collectors.toMap(it -> encode(it.getKey()), it -> encode(it.getValue())));
final TreeMap<String, String> sorted = new TreeMap<>(encoded);
return sorted.entrySet().stream()
.map(entry -> entry.getKey().concat(encode("=")).concat(entry.getValue()))
.collect(Collectors.joining(encode("&")));
}
}
import java.util.Base64;
import java.util.Map;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
public class SignatureUtil {
private static final String DELIMITER = "&";
public static String signature(final String method, final String url,
final Map<String, String> parameters, final String consumerSecret, final String userSecret) {
String signatureBaseString = method.toUpperCase().concat(DELIMITER)
.concat(PercentUtil.encode(url));
if (!parameters.isEmpty()) {
signatureBaseString = signatureBaseString.concat(DELIMITER)
.concat(PercentUtil.encode(parameters));
}
System.out.println(signatureBaseString);
final String signingKey = PercentUtil.encode(consumerSecret).concat(DELIMITER)
.concat(PercentUtil.encode(userSecret));
final String binaryRepresentation = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, signingKey)
.hmacHex(signatureBaseString);
try {
return Base64.getEncoder().encodeToString(Hex.decodeHex(binaryRepresentation));
} catch (DecoderException e) {
// todo think to not catch the exception and do it later in the business logic
throw new RuntimeException("Cannot decode the binary representation of the signature");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment