OAuthIdentifyService.java

package org.wikidata.query.rdf.mwoauth;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.github.scribejava.core.model.OAuth1AccessToken;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth10aService;

import lombok.SneakyThrows;

public class OAuthIdentifyService {
    private static final String USERNAME = "username";
    private final OAuth10aService service;
    private final String url;
    private final JWTVerifier verifier;

    public OAuthIdentifyService(OAuth10aService service, String indexUrl, String consumerSecret) {
        this.service = service;
        this.url = indexUrl + "?title=Special:OAuth/identify";
        verifier = JWT.require(Algorithm.HMAC256(consumerSecret)).withClaimPresence(USERNAME).build();
    }

    @SneakyThrows
    public Optional<String> getUsername(OAuth1AccessToken accessToken) {
        return identify(accessToken).map(token -> token.getClaim(USERNAME).asString());
    }

    private Optional<DecodedJWT> identify(OAuth1AccessToken accessToken) throws InterruptedException, ExecutionException, IOException {
        return execute(new OAuthRequest(Verb.GET, url), accessToken);
    }

    private Optional<DecodedJWT> execute(OAuthRequest request, OAuth1AccessToken accessToken) throws InterruptedException, ExecutionException, IOException {
        service.signRequest(accessToken, request);
        try (Response response = service.execute(request)) {
            if (!response.isSuccessful()) {
                // Probably an html error page as opposed to a rejected request.
                return Optional.empty();
            }
            try {
                return Optional.of(verifier.verify(response.getBody()));
            } catch (JWTVerificationException e) {
                // response.body probably contains some json that indicates what exactly went wrong,
                // in many cases this probably indicates a token that is now invalid.
                return Optional.empty();
            }
        }
    }
}