001/* 002 * Copyright (c) 2010-2024 Mark Allen, Norbert Bartels. 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining a copy 005 * of this software and associated documentation files (the "Software"), to deal 006 * in the Software without restriction, including without limitation the rights 007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 008 * copies of the Software, and to permit persons to whom the Software is 009 * furnished to do so, subject to the following conditions: 010 * 011 * The above copyright notice and this permission notice shall be included in 012 * all copies or substantial portions of the Software. 013 * 014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 020 * THE SOFTWARE. 021 */ 022package com.restfb; 023 024import static com.restfb.util.ObjectUtil.verifyParameterPresence; 025 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.List; 029 030import com.restfb.exception.FacebookResponseContentException; 031import com.restfb.scope.ScopeBuilder; 032 033/** 034 * The default implementation to work with the Instagram Basic Display API. 035 * <p> 036 * it is used for this Instagram API and for the Threads API. This API is accordingly to the reference based on the 037 * Instagram Basic Display API. 038 * 039 * @deprecated on December 2024 see blog post: <a href= 040 * "https://developers.facebook.com/blog/post/2024/09/04/update-on-instagram-basic-display-api/">https://developers.facebook.com/blog/post/2024/09/04/update-on-instagram-basic-display-api/</a> 041 */ 042@Deprecated 043public class DefaultInstagramClient extends DefaultFacebookClient { 044 045 public DefaultInstagramClient(Version version) { 046 super(version); 047 } 048 049 public DefaultInstagramClient(String accessToken, Version apiVersion) { 050 super(accessToken, apiVersion); 051 } 052 053 public DefaultInstagramClient(String accessToken, String appSecret, Version apiVersion) { 054 super(accessToken, appSecret, apiVersion); 055 } 056 057 public DefaultInstagramClient(String accessToken, WebRequestor webRequestor, JsonMapper jsonMapper, 058 Version apiVersion) { 059 super(accessToken, webRequestor, jsonMapper, apiVersion); 060 } 061 062 public DefaultInstagramClient(String accessToken, String appSecret, WebRequestor webRequestor, JsonMapper jsonMapper, 063 Version apiVersion) { 064 super(accessToken, appSecret, webRequestor, jsonMapper, apiVersion); 065 } 066 067 @Override 068 public String getLoginDialogUrl(String appId, String redirectUri, ScopeBuilder scope, String state, 069 Parameter... parameters) { 070 List<Parameter> parameterList = new ArrayList<>(); 071 Collections.addAll(parameterList, parameters); 072 parameterList.add(Parameter.with("response_type", CODE)); 073 return getGenericLoginDialogUrl(appId, redirectUri, scope, 074 () -> getFacebookEndpointUrls().getInstagramApiEndpoint() + "/oauth/authorize", state, parameterList); 075 } 076 077 @Override 078 public String getLoginDialogUrl(String appId, String redirectUri, ScopeBuilder scope, Parameter... parameters) { 079 return getLoginDialogUrl(appId, redirectUri, scope, null, parameters); 080 } 081 082 @Override 083 public AccessToken obtainUserAccessToken(String clientId, String clientSecret, String redirectUri, String code) { 084 verifyParameterPresence(CLIENT_ID, clientId); 085 verifyParameterPresence(PARAM_CLIENT_SECRET, clientSecret); 086 verifyParameterPresence(CODE, code); 087 verifyParameterPresence(REDIRECT_URI, redirectUri); 088 089 return publish(PATH_OAUTH_ACCESS_TOKEN, AccessToken.class, // 090 Parameter.with(CLIENT_ID, clientId), // 091 Parameter.with(PARAM_CLIENT_SECRET, clientSecret), // 092 Parameter.with(CODE, code), // 093 Parameter.with(GRANT_TYPE, "authorization_code"), // 094 Parameter.with(REDIRECT_URI, redirectUri)); 095 } 096 097 @Override 098 public AccessToken obtainExtendedAccessToken(String appId, String appSecret, String accessToken) { 099 throw new UnsupportedOperationException("Not supported, use the other obtainExtendedAccessToken instead"); 100 } 101 102 @Override 103 public AccessToken obtainExtendedAccessToken(String appId, String appSecret) { 104 verifyParameterPresence(APP_SECRET, appSecret); 105 verifyParameterPresence("accessToken", accessToken); 106 107 String response = makeRequest("access_token", false, false, null, // 108 Parameter.with(PARAM_CLIENT_SECRET, appSecret), // 109 Parameter.with(GRANT_TYPE, "ig_exchange_token"), // 110 Parameter.withFields("access_token,expires_in,token_type")); 111 112 try { 113 return getAccessTokenFromResponse(response); 114 } catch (Exception t) { 115 throw new FacebookResponseContentException(CANNOT_EXTRACT_ACCESS_TOKEN_MESSAGE, t); 116 } 117 } 118 119 /** 120 * Obtain a refreshed Instagram extended access token. 121 * 122 * <p> 123 * This method is used to refresh an existing Instagram extended access token. Extended access tokens expire after a 124 * certain period of time, and this method allows you to obtain a new one using the refresh token provided with the 125 * original extended access token. 126 * 127 * @return A new {@link AccessToken} object containing the refreshed access token, expiration time, and token type. 128 * @throws FacebookResponseContentException 129 * If the response from the Facebook API cannot be parsed or if the access token cannot be extracted from 130 * the response. 131 */ 132 @Override 133 public AccessToken obtainRefreshedExtendedAccessToken() { 134 String response = makeRequest("refresh_access_token", false, false, null, // 135 Parameter.with(GRANT_TYPE, "ig_refresh_token"), // 136 Parameter.withFields("access_token,expires_in,token_type")); 137 try { 138 return getAccessTokenFromResponse(response); 139 } catch (Exception t) { 140 throw new FacebookResponseContentException(CANNOT_EXTRACT_ACCESS_TOKEN_MESSAGE, t); 141 } 142 } 143 144 @Override 145 public FacebookClient createClientWithAccessToken(String accessToken) { 146 return new DefaultInstagramClient(accessToken, this.appSecret, getWebRequestor(), getJsonMapper(), this.apiVersion); 147 } 148 149 @Override 150 protected String createBaseUrlForEndpoint(String apiCall, boolean hasAttachment, boolean hasReel) { 151 String baseUrl = getInstagramGraphEndpointUrl(); 152 if (apiCall.startsWith("oauth")) { 153 baseUrl = getFacebookEndpointUrls().getInstagramApiEndpoint(); 154 } 155 156 return baseUrl; 157 } 158 159 private String getInstagramGraphEndpointUrl() { 160 if (apiVersion.isUrlElementRequired()) { 161 return getFacebookEndpointUrls().getInstagramEndpoint() + '/' + apiVersion.getUrlElement(); 162 } else { 163 return getFacebookEndpointUrls().getInstagramEndpoint(); 164 } 165 } 166}