Skip to content

Commit 3a095e2

Browse files
committed
feat: added polar oauth2 api and example
1 parent ea42bc9 commit 3a095e2

5 files changed

Lines changed: 276 additions & 0 deletions

File tree

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.github.scribejava.apis;
2+
3+
import com.github.scribejava.apis.polar.PolarJsonTokenExtractor;
4+
import com.github.scribejava.apis.polar.PolarOAuth20Service;
5+
import com.github.scribejava.core.builder.api.DefaultApi20;
6+
import com.github.scribejava.core.extractors.TokenExtractor;
7+
import com.github.scribejava.core.httpclient.HttpClient;
8+
import com.github.scribejava.core.httpclient.HttpClientConfig;
9+
import com.github.scribejava.core.model.OAuth2AccessToken;
10+
import com.github.scribejava.core.oauth.OAuth20Service;
11+
12+
import java.io.OutputStream;
13+
14+
/**
15+
* Polar's OAuth2 client's implementation
16+
* source: https://www.polar.com/accesslink-api/#authentication
17+
*/
18+
public class PolarAPI20 extends DefaultApi20 {
19+
20+
protected PolarAPI20() {
21+
}
22+
23+
private static class InstanceHolder {
24+
25+
private static final PolarAPI20 INSTANCE = new PolarAPI20();
26+
}
27+
28+
public static PolarAPI20 instance() {
29+
return PolarAPI20.InstanceHolder.INSTANCE;
30+
}
31+
32+
@Override
33+
public String getAccessTokenEndpoint() {
34+
return "https://polarremote.com/v2/oauth2/token";
35+
}
36+
37+
@Override
38+
protected String getAuthorizationBaseUrl() {
39+
return "https://flow.polar.com/oauth2/authorization";
40+
}
41+
42+
@Override
43+
public OAuth20Service createService(String apiKey, String apiSecret, String callback, String defaultScope, String responseType,
44+
OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) {
45+
46+
return new PolarOAuth20Service(this, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent,
47+
httpClientConfig, httpClient);
48+
}
49+
50+
@Override
51+
public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() {
52+
return PolarJsonTokenExtractor.instance();
53+
}
54+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.scribejava.apis.polar;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor;
5+
import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse;
6+
import com.github.scribejava.core.oauth2.OAuth2Error;
7+
8+
import java.io.IOException;
9+
10+
/**
11+
* Token related documentation: https://www.polar.com/accesslink-api/#token-endpoint
12+
*/
13+
public class PolarJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor {
14+
15+
protected PolarJsonTokenExtractor() {
16+
}
17+
18+
private static class InstanceHolder {
19+
20+
private static final PolarJsonTokenExtractor INSTANCE = new PolarJsonTokenExtractor();
21+
}
22+
23+
public static PolarJsonTokenExtractor instance() {
24+
return InstanceHolder.INSTANCE;
25+
}
26+
27+
@Override
28+
protected PolarOauth2AccessToken createToken(String accessToken, String tokenType, Integer expiresIn,
29+
String refreshToken, String scope, JsonNode response, String rawResponse) {
30+
return new PolarOauth2AccessToken(accessToken, tokenType, expiresIn, refreshToken, scope,
31+
response.get("x_user_id").asText(), rawResponse);
32+
}
33+
34+
@Override
35+
public void generateError(String rawResponse) throws IOException {
36+
final JsonNode errorNode = OAuth2AccessTokenJsonExtractor.OBJECT_MAPPER.readTree(rawResponse)
37+
.get("errors").get(0);
38+
39+
OAuth2Error errorCode;
40+
try {
41+
errorCode = OAuth2Error.parseFrom(extractRequiredParameter(errorNode, "errorType", rawResponse).asText());
42+
} catch (IllegalArgumentException iaE) {
43+
//non oauth standard error code
44+
errorCode = null;
45+
}
46+
47+
throw new OAuth2AccessTokenErrorResponse(errorCode, errorNode.get("message").asText(), null, rawResponse);
48+
}
49+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.github.scribejava.apis.polar;
2+
3+
import com.github.scribejava.core.builder.api.DefaultApi20;
4+
import com.github.scribejava.core.httpclient.HttpClient;
5+
import com.github.scribejava.core.httpclient.HttpClientConfig;
6+
import com.github.scribejava.core.model.OAuthConstants;
7+
import com.github.scribejava.core.model.OAuthRequest;
8+
import com.github.scribejava.core.oauth.AccessTokenRequestParams;
9+
import com.github.scribejava.core.oauth.OAuth20Service;
10+
import com.github.scribejava.core.pkce.PKCE;
11+
12+
import java.io.OutputStream;
13+
14+
public class PolarOAuth20Service extends OAuth20Service {
15+
16+
public PolarOAuth20Service(DefaultApi20 api, String apiKey, String apiSecret, String callback, String defaultScope, String responseType,
17+
OutputStream debugStream, String userAgent, HttpClientConfig httpClientConfig, HttpClient httpClient) {
18+
super(api, apiKey, apiSecret, callback, defaultScope, responseType, debugStream, userAgent, httpClientConfig, httpClient);
19+
}
20+
21+
@Override
22+
protected OAuthRequest createAccessTokenRequest(AccessTokenRequestParams params) {
23+
final OAuthRequest request = new OAuthRequest(getApi().getAccessTokenVerb(), getApi().getAccessTokenEndpoint());
24+
25+
getApi().getClientAuthentication().addClientAuthentication(request, getApiKey(), getApiSecret());
26+
27+
request.addBodyParameter(OAuthConstants.CODE, params.getCode());
28+
final String callback = getCallback();
29+
if (callback != null) {
30+
request.addBodyParameter(OAuthConstants.REDIRECT_URI, callback);
31+
}
32+
request.addBodyParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.AUTHORIZATION_CODE);
33+
34+
final String pkceCodeVerifier = params.getPkceCodeVerifier();
35+
if (pkceCodeVerifier != null) {
36+
request.addBodyParameter(PKCE.PKCE_CODE_VERIFIER_PARAM, pkceCodeVerifier);
37+
}
38+
if (isDebug()) {
39+
log("created access token request with body params [%s], query string params [%s]",
40+
request.getBodyParams().asFormUrlEncodedString(),
41+
request.getQueryStringParams().asFormUrlEncodedString());
42+
}
43+
return request;
44+
}
45+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.github.scribejava.apis.polar;
2+
3+
import com.github.scribejava.core.model.OAuth2AccessToken;
4+
5+
import java.util.Objects;
6+
7+
public class PolarOauth2AccessToken extends OAuth2AccessToken {
8+
9+
private String userId;
10+
11+
public PolarOauth2AccessToken(
12+
String accessToken, String tokenType, Integer expiresIn, String refreshToken, String scope, String userId, String rawResponse) {
13+
super(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse);
14+
this.userId = userId;
15+
}
16+
17+
public String getUserId() {
18+
return userId;
19+
}
20+
21+
@Override
22+
public int hashCode() {
23+
int hash = super.hashCode();
24+
hash = 37 * hash + Objects.hashCode(userId);
25+
return hash;
26+
}
27+
28+
@Override
29+
public boolean equals(Object obj) {
30+
if (this == obj) {
31+
return true;
32+
}
33+
if (obj == null) {
34+
return false;
35+
}
36+
if (getClass() != obj.getClass()) {
37+
return false;
38+
}
39+
if (!super.equals(obj)) {
40+
return false;
41+
}
42+
43+
return Objects.equals(userId, ((PolarOauth2AccessToken) obj).getUserId());
44+
}
45+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.github.scribejava.apis.examples;
2+
3+
import com.github.scribejava.apis.PolarAPI20;
4+
import com.github.scribejava.apis.polar.PolarOauth2AccessToken;
5+
import com.github.scribejava.core.builder.ServiceBuilder;
6+
import com.github.scribejava.core.model.OAuth2AccessToken;
7+
import com.github.scribejava.core.model.OAuthRequest;
8+
import com.github.scribejava.core.model.Response;
9+
import com.github.scribejava.core.model.Verb;
10+
import com.github.scribejava.core.oauth.OAuth20Service;
11+
12+
import java.util.Scanner;
13+
14+
/**
15+
* @author Alex Vidrean
16+
* @since 13-Oct-19
17+
*/
18+
public class PolarAPI20Example {
19+
20+
private static final String NETWORK_NAME = "Polar";
21+
22+
private static final String PROTECTED_RESOURCE_URL = "https://www.polaraccesslink.com/v3/users/%s";
23+
24+
private PolarAPI20Example() {
25+
}
26+
27+
@SuppressWarnings("PMD.SystemPrintln")
28+
public static void main(String... args) throws Exception {
29+
30+
// Replace these with your client id and secret fron your app
31+
final String clientId = "1a86ac29-7ea3-473a-81d9-8ea582214558";
32+
final String clientSecret = "0dc23e1d-b677-4da0-bb14-311949898a95";
33+
final String scope = "accesslink.read_all";
34+
final String callback = "http://localhost";
35+
final OAuth20Service service = new ServiceBuilder(clientId).apiSecret(clientSecret).defaultScope(scope)
36+
//your callback URL to store and handle the authorization code sent by Polar
37+
.callback(callback).build(PolarAPI20.instance());
38+
final Scanner in = new Scanner(System.in);
39+
40+
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
41+
System.out.println();
42+
43+
// Obtain the Authorization URL
44+
System.out.println("Fetching the Authorization URL...");
45+
final String authorizationUrl = service.getAuthorizationUrl("some_params");
46+
System.out.println("Got the Authorization URL!");
47+
System.out.println("Now go and authorize ScribeJava here:");
48+
System.out.println(authorizationUrl);
49+
System.out.println("And paste the authorization code here");
50+
System.out.print(">>");
51+
final String code = in.nextLine();
52+
System.out.println();
53+
54+
System.out.println("Trading the Authorization Code for an Access Token...");
55+
System.out.println("Got the Access Token!");
56+
final OAuth2AccessToken oauth2AccessToken = service.getAccessToken(code);
57+
System.out.println("(if your curious it looks like this: " + oauth2AccessToken + ", 'rawResponse'='" + oauth2AccessToken.getRawResponse() + "')");
58+
System.out.println();
59+
60+
if (!(oauth2AccessToken instanceof PolarOauth2AccessToken)) {
61+
System.out.println("oauth2AccessToken is not instance of PolarOAuth2AccessToken. Strange enough. exit.");
62+
return;
63+
}
64+
65+
final PolarOauth2AccessToken accessToken = (PolarOauth2AccessToken) oauth2AccessToken;
66+
67+
// Now let's go and ask for a protected resource!
68+
// This will get the profile for this user
69+
System.out.println("Now we're going to access a protected resource...");
70+
71+
final OAuthRequest request = new OAuthRequest(Verb.GET, String.format(PROTECTED_RESOURCE_URL, accessToken.getUserId()));
72+
request.addHeader("Accept", "application/json");
73+
74+
service.signRequest(accessToken, request);
75+
76+
System.out.println();
77+
try (Response response = service.execute(request)) {
78+
System.out.println(response.getCode());
79+
System.out.println(response.getBody());
80+
}
81+
System.out.println();
82+
}
83+
}

0 commit comments

Comments
 (0)