Keycloak - How to refresh token witj Java client? - java

I'm looking for refresh token by using the Java Admin Client https://github.com/keycloak/keycloak/tree/master/integration/admin-client
Cannot find anything about it
Regards
EDIT :
finally I go that :
public AccessTokenResponse executeRefresh(String refreshToken) {
String url = "https://url/auth" + "/realms/" + keycloakRealm + "/protocol/openid-connect/token";
Configuration kcConfig = new Configuration(authServerUrl, keycloakRealm, keycloakInternalClientId, null, null);
Http http = new Http(kcConfig, (params, headers) -> {
});
return http.<AccessTokenResponse>post(url)
.authentication()
.client()
.form()
.param("grant_type", "refresh_token")
.param("refresh_token", refreshToken)
.param("client_id", keycloakInternalClientId)
.param("client_secret", keycloakInternalClientSecret)
.response()
.json(AccessTokenResponse.class)
.execute();
}

org.keycloak.admin.client.Keycloak.tokenManager().refreshToken() can refresh token. For example:
// Create a Keycloak client
Keycloak kc = KeycloakBuilder.builder()
.serverUrl("http://localhost:8080/auth")
.realm("master")
.username("admin")
.password("password")
.clientId("admin-cli")
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build())
.build();
TokenManager tokenManager = kc.tokenManager();
// get access token
AccessTokenResponse accessTokenResponse = tokenManager.getAccessToken();
System.out.println(accessTokenResponse.getRefreshToken());
// Refresh token
accessTokenResponse = tokenManager.refreshToken();
System.out.println(accessTokenResponse.getRefreshToken());

Sadly Java Admin Client does not have this kind of functionality (hopefully will have in the future)
For now, look at this answer:
Refresh access_token via refresh_token in Keycloak

Have achieved it through RestTemplate inside my spring-boot application.
Below is the code I have used to get refresh token :-
public ResponseEntity<RefreshTokenResponse> refreshToken(String refreshToken) {
String url = authUrl+ "/realms/" + realm + "/protocol/openid-connect/token";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "refresh_token");
map.add("refresh_token", refreshToken);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
ResponseEntity response =
restTemplate.exchange(url,
HttpMethod.POST,
entity,
Object.class);
return response;}
RefreshTokenResponse :-
#Data
public class RefreshTokenResponse {
private AccessTokenResponse token;
}
Keycloak v19.0.0
authUrl :- where keycloak server is running. my case
http://localhost:8080/
ream :- your realm name

Actually, I managed to make Keycloak client do this job for me after spending some time with the issue. In my case I had to connect to a Keycloak server with password grant type, and use access token to fetch data from a third party protected endpoint in a Spring Boot server side application.
At the end I came up with a service, which provides an access token after initial authentication, and automatic refresh/re-authentication on demand.
I added a #Configuration bean, which contained the connection parameters to the third party Keycloak instance:
package no.currentclient.application.api.config; // real package name masked
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class OauthClientConfig {
public record OauthConfig(String realm, String authServerUrl, String clientId, String username, String password) {
}
#Bean
OauthConfig oauthConfig(
#Value("${client.oauth.realm}") String realm,
#Value("${client.oauth.auth-server-url}") String authServerUrl,
#Value("${client.oauth.resource}") String clientId,
#Value("${client.oauth.username}") String username,
#Value("${client.oauth.password}") String password
) {
return new OauthConfig(realm,
authServerUrl,
clientId,
username,
password);
}
}
After I created a Spring Service which is capable of authenticating, getting and refreshing an access token:
package no.currentclient.application.auth.oauthclient; // real package name masked
import com.fasterxml.jackson.databind.ObjectMapper;
import no.currentclient.application.api.config.OauthClientConfig;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.TokenCallable;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Collections;
#Service
public class OauthTokenService {
private final TokenCallable tokenCallable;
public OauthTokenService(
OauthClientConfig.OauthConfig oauthConfig,
OkHttpClient okHttpClient
) throws IOException {
var serverConfiguration = getServerConfiguration(oauthConfig.authServerUrl()+"/auth/realms/"+oauthConfig.realm()+"/.well-known/openid-configuration", okHttpClient);
var config = new org.keycloak.authorization.client.Configuration(
// These might all be set to null -> only tokenMinimumTimeToLive is used in TokenCallable...
null,null,null, null,null);
var http = new Http(config, (requestParams, requestHeaders) -> requestParams.put("client_id", Collections.singletonList("deichman")));
tokenCallable = new TokenCallable(oauthConfig.username(), oauthConfig.password(), http, config, serverConfiguration);
}
/*
* Call this method to get hold of an on-demand refreshed auth token. TokenCallable handles the burden of token
* refresh and re-authentication in case of session timeout.
*/
public String getAccessToken() {
return tokenCallable.call();
}
private ServerConfiguration getServerConfiguration(String configUrl, OkHttpClient okHttpClient) throws IOException {
var configRequest = new Request.Builder().url(configUrl).get().build();
try (var response = okHttpClient.newCall(configRequest).execute()) {
return new ObjectMapper().readValue(response.body().string(), ServerConfiguration.class);
}
}
}
TokenCallable hides all the complexity of refresh/re-authentication on demand.
Hope it helps a few struggling with this problem.

Related

How to cache token with Microsoft Graph for Java

I am using Microsoft Graph SDK for some requests however everytime I perform a GET request it does another request to get a token. I've tried reading documentation about this but I cannot find anything in Java.
Here is my implementation of my client
ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
.clientId(clientId)
.clientSecret(clientSecret)
.tenantId(tenantId)
.httpClient(httpClient)
.build();
I have also tried using the method .tokenCachePersistenceOptions() in my builder but I get this warning/error
c.m.a.m.CrossProcessCacheFileLock : null
Thank you!
To achieve the above requirement Firstly you need to Authenticate for implementing MSAL to get the token from Azure AD.
To obtain an access token, your app must be registered with the Microsoft identity platform and approved to access the Microsoft Graph resources it requires by either a user who is added as an owner for that application or an administrator.
For complete setup please refer this MS DOCUMENT Authentication and authorization basics for Microsoft Graph , This sample & GitHub sample|msgraph-sdk-java-core
I was looking for the same think and here's what I've implemented for it:
Implement your own authentication provider class:
public class DelegateAuthenticationProvider implements IAuthenticationProvider {
private String token;
public DelegateAuthenticationProvider(String token) {
this.token = token;
}
#NotNull
#Override
public CompletableFuture<String> getAuthorizationTokenAsync(#NotNull URL url) {
return CompletableFuture.completedFuture(token);
}
}
Then you can use it as follow:
String token = "<YOUR_TOKEN_STRING>"
IAuthenticationProvider tokenCredentialAuthProvider = new DelegateAuthenticationProvider(token);
// Create the Graph Client with the given Token Provider
GraphServiceClient graphClient = GraphServiceClient.builder()
.authenticationProvider(tokenCredentialAuthProvider)
.buildClient();
If you get an GraphServiceException code 401 you should renew your token.
When you are successfully logged in with your clientSecretCredential, here's how you can get the token:
List<String> scopes = Arrays.asList("https://graph.microsoft.com/.default");
IAuthenticationProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(scopes, clientSecretCredential);
String token = tokenCredentialAuthProvider.getAuthorizationTokenAsync("https://graph.microsoft.com/v1.0/me").get()
Hope this helps.
You can override the authenticationProvider which is provided for the GraphServiceClient
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenCredential;
import com.azure.core.credential.TokenRequestContext;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import org.jetbrains.annotations.NotNull;
import java.net.URL;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public class CachingTokenCredentialAuthProvider extends TokenCredentialAuthProvider {
private final TokenCredential tokenCredential;
private final TokenRequestContext context;
private AccessToken accessToken;
public CachingTokenCredentialAuthProvider(#NotNull List<String> scopes, #NotNull TokenCredential tokenCredential) {
super(scopes, tokenCredential);
if (!scopes.isEmpty()) {
this.context = new TokenRequestContext();
this.context.setScopes(scopes);
this.tokenCredential = Objects.requireNonNull(tokenCredential, "tokenCredential parameter cannot be null.");
} else {
throw new IllegalArgumentException("scopes parameter cannot be null or empty");
}
}
#NotNull
#Override
public CompletableFuture<String> getAuthorizationTokenAsync(#NotNull URL requestUrl) {
if (this.shouldAuthenticateRequestWithUrl(Objects.requireNonNull(requestUrl, "requestUrl parameter cannot be null"))) {
if(this.accessToken != null && !OffsetDateTime.now().minusMinutes(1).isAfter(this.accessToken.getExpiresAt())) {
return CompletableFuture.completedFuture(this.accessToken.getToken());
}
return this.tokenCredential.getToken(this.context).toFuture().thenApply(accessToken -> {
saveToken(accessToken);
return accessToken.getToken();
});
} else {
return CompletableFuture.completedFuture(null);
}
}
void saveToken(AccessToken accessToken) {
this.accessToken = accessToken;
}
}
This will cache the token until it one minute before it is no longer valid.

Spring Boot RESTful Web Service to post json content to https(secure) url

I am searching for working code sample/ snippet of spring boot to post json content to HTTPS restful web service(developed in python). Below is sample code of standalone program which does the same, But I want to do it in spring boot Restful app. I found many examples in google and stack overflows example example but these are for get request and not suites for what I am looking for. Someone please share full working example for "https post request using spring boot service".
Thanks in advance.
import java.io.PrintStream;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
public class App{
public static void main(String []args) throws NoSuchAlgorithmException, KeyManagementException{
String https_url = "https://192.168.4.5:55543/books";
String content = "{\"data\":{\"a\"}}";
System.setProperty("javax.net.useSystemProxies", "true");
System.setProperty("javax.net.ssl.keyStore", "C:/cert/client.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "testdev");
System.setProperty("javax.net.ssl.trustStore", "C:/cert/server.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "testdev");
System.setProperty("jdk.tls.client.protocals", "TLSv1.2");
System.setProperty("https.protocals", "TLSv1.2");
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> { return true;});
URL url = new URL(https_url);
HttpsURLConnection https_con = (HttpsURLConnection) url.openConnection();
https_con.setRequestProperty("Content-Type", "application/json");
https_con.setRequestMethod("POST");
https_con.setDoOutput(true);
PrintStream ps = new PrintStream(https_con.getOutputStream());
ps.println(content);
ps.close();
https_con.connect();
https_con.getResponseCode();
https_con.disconnect();
}
}
Ok, so here is the forked Github repo.
Following are the changes I made:
secure-server -> Added post endpoint with simply String payload:
#RestController
public class HomeRestController {
//...
#PostMapping(value = "/", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String consumeData(#RequestBody String data, Principal principal){
return String.format("Hello %s! You sent: %s", principal.getName(), data);
}
}
secure-client -> added call to that post method:
#RestController
public class HomeRestController {
// . . .
#GetMapping("/post")
public String post() throws RestClientException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String data = "Test payload";
HttpEntity<String> request = new HttpEntity<>(data, headers);
return restTemplate.postForEntity("https://localhost:8443", request , String.class ).getBody();
}
}
So, when you make call to client endpoint as:
http://localhost:8086/post
You will get response:
Hello codependent-client! You sent: Test payload

How JSON web token works in Spring boot?

I want to write REST service and I choose JWT for securing this rest service.
I declare 1 min for token, afterwards what I must do?
I must refresh token or something else?
If I must refresh token, user can call service's method with this token?
Token code
package com.example.demo.config;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.ArrayList;
import java.util.Arrays;
public class TokenAuthenticationService {
//field of conf
static final long EXPIRATIONTIME = 60_000; // 1 min
static final String SECRET = "msg";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
//generate token
public static void addAuthentication(HttpServletResponse res, Authentication auth) {
String concattedRoles = "";
for (GrantedAuthority ga : auth.getAuthorities()) {
if (!"".equals(concattedRoles))
concattedRoles += "," + ga.getAuthority();
else
concattedRoles += ga.getAuthority();
}
String JWT = Jwts.builder().setSubject(auth.getName()).claim("roles", concattedRoles)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET).compact();
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT);
}
//get token from request header.
public static Authentication getAuthentication(HttpServletRequest request) {
try {
System.out.println("(Authentication getAuthentication(HttpServletRequest request)");
String token = request.getHeader(HEADER_STRING);
System.out.println("token=>"+token);
if (token != null) {
Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
String user = claims.getSubject();
String roles = (String) claims.get("roles");
if(claims.getExpiration().before(new Date(System.currentTimeMillis())))
throw new Exception(); //Here trow exception.
List<String> roleList = Arrays.asList(roles.split("\\s*,\\s*"));
List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
for (int i = 0; i < roleList.size(); i++) {
System.out.println(roleList.get(i));
SimpleGrantedAuthority abv = new SimpleGrantedAuthority(roleList.get(i));
grantedAuths.add(abv);
}
System.out.println(grantedAuths);
return user != null ? new UsernamePasswordAuthenticationToken(user, null, grantedAuths) : null;
}
return null;
}catch (Exception e){
System.out.println(e);
return null;
}
}
}
How we implemented is -
First time user logs in we send them a token and a refresh token.
Client side then uses the 'token' in the header to make further API calls.
At client side, we maintain e countdown of 15 minutes (which is lesser than the expiry time of the main token), after which from the client side we send a request to the server with both token and refresh token.
After getting a valid refresh token along with the main token, the server sends back a new token with increased exipiry time.
Hope this helps.
Basically refresh_token is used for giving back a valid access_token to the user upon request. And refresh_tokens are usually long-lived rather than short-lived.
Personally, my design for securing a RESTful API is just to let them request the access_token to my endpoint i.e https://api.example.com/oauth/token every time, I don't provide a refresh_token because the idea for me is just to let them in into the resource, nothing else. And usually, the requesting resource will not be staying for so long on a particular session. For the other concerns of the server getting too many requests on the same user/session, you can implement a rate-limiting to your servers or token endpoint.
I based my API security implementations on PayPal and JHipster. They do not provide refresh_tokens to their respective RESTful API implementations, because in the end, refresh_tokens are optional to be used, and it's just a matter of what you want to achieve upon securing your RESTful endpoints.
For more information about refresh_token you can these links:
When to use JWT Tokens and Understanding refresh tokens.

Spring Boot way of implementing the command HTTP OPTIONS with credentials in header

I am new to the Spring Boot, but I have worked with Java before on HTTP OPTIONS command.
I am building a service method that takes in an URL and test that URL using HTTP OPTIONS command.
Below is what I have written using Java:
import java.net.HttpURLConnection;
import java.net.URL;
...
public String testConnection(URL url) {
try {
String type = "text/plain;charset=UTF-8";
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("OPTIONS");
conn.setRequestProperty("Content-Type", type);
System.out.println(String.format("HTTP %d: %s",
conn.getResponseCode(), conn.getResponseMessage()));
for(String header : conn.getHeaderFields().keySet() ){
System.out.println(String.format("%s : %s",
header, conn.getHeaderFields().get(header)));
}
String rMessage = conn.getResponseMessage();
System.out.println ("Response " + rMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Is there a Spring Boot equivalent way of implementing the HTTP OPTIONS request? If so, could I also add credentials (username and password) to the header as part of the request? Thanks.
You can use Spring Boot's RestTemplate:
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
// skipping class definition here, just showing the method call
private void optionsCall() {
final String url = "https://some.server/with/some/path";
final String user = "theUser";
final String password = "thePassword";
final String authHeaderValue = "Basic " + Base64.getEncoder()
.encodeToString((user + ':' + password).getBytes());
final HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("Authorization", authHeaderValue);
RestTemplate rest = new RestTemplate();
final ResponseEntity<Object> optionsResponse =
rest.exchange(url, HttpMethod.OPTIONS,
new HttpEntity<>(requestHeaders),
Object.class);
optionsResponse.getHeaders().forEach((key, value) -> log.info("{} -> {}", key, value));
}
I use an Object here for the response body type, normally an OPTION request does not return something, but it is not forbidden to do so, and the exchange method wants to have a class there. I log the returned headers using an slf4j Logger. Tested against a service using https and basic authentication.

How to create a oAuth request using java?

I need to make a connection with Viagogo website using oAuth. Referring to their documentation I need to create a request similar to the following one
Using the example in step 1A, this means you may generate a signature base string that looks like the following:
GET&http%3A%2F%2Fapi.viagogo.net%2FPublic%2FSimpleOAuthAccessRequest&oauth_consumer_key%3Dtestkey%26oauth_nonce%3Dmyn0nc3%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1292404912%26oauth_version%3D1.0%26scope%3DAPI.Public
I am using the following code but when I comment lines 1,2 it return unauthorized error, and when I use them it shows oauthService.signRequest returns void.
TradeKingAPI.java
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
}
main.java
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;
import api.TradeKingAPI;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.OAuthConstants;
import org.scribe.oauth.OAuthService;
........
OAuthService oauthService = new ServiceBuilder()
.provider(TradeKingAPI.class)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Long seconds = (System.currentTimeMillis() / 1000);
System.out.println(">>>" + seconds);
String stSeconds = seconds.toString();
OAuthRequest request = new OAuthRequest(Verb.GET, "http://api.viagogo.net/Public
/SimpleOAuthAccessRequest");
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "My consumer key");
request.addOAuthParameter(OAuthConstants.NONCE, "myn0nc3");
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, "HMAC-SHA1");
request.addOAuthParameter(OAuthConstants.TIMESTAMP, seconds.toString());
request.addOAuthParameter(OAuthConstants.VERSION, "1.0");
request.addOAuthParameter("scope", "API.Public");
1 String signature = oauthService.signRequest(OAuthConstants.EMPTY_TOKEN, request);
2 request.addOAuthParameter(OAuthConstants.SIGNATURE,signature);
Response response = request.send();
System.err.println(">>" + response.isSuccessful());
System.err.println(">>" + response.getMessage());
System.err.println(">>" + response.getBody());
From what I understand from Viagogo public API access documentation, the token you get in the step 1, is the equivalent to a request token in a complete OAuth 1.0a "dance".
So, you should be able to use scribe-java internal classes to get this token without doing it by hand. The only difference is that in scribe, this request sends also a callback url to the OAuth server for the next step of OAuth "dance".
As I can't get a consumer account I can only make assumption here. So let's have 2 scenarios :
Scenario 1 : Viagogo server tolerate extra parameter (i.e. call back URL)
so you can go with this code
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "none";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "none";
}
}
Then your calling code will be :
OAuthService service = new ServiceBuilder()
.provider(TradeKingAPI.class)
.signatureType(QueryString)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Token requestToken = service.getRequestToken();
//make your API calls
OAuthRequest request = new OAuthRequest(Verb.GET,
"http://api.viagogo.net/Public/Event/235");
service.signRequest(requestToken, request);
Response response = request.send();
System.out.println(response.getBody());
But as I said, if Viagogo security is a bit strict and it refuses the useless param oauth_callback, you'll need to switch to scenario 2
Scenario 2 : Build your own OAuthService
In this scenario you have to create a new OAuthService to avoid dealing with OAuthCallback parameter.
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.*;
import org.scribe.oauth.OAuth10aServiceImpl;
import java.util.Map;
public class OAuth10aServiceForViagogo extends OAuth10aServiceImpl {
private OAuthConfig config;
private DefaultApi10a api;
public OAuth10aServiceForViagogo(DefaultApi10a api, OAuthConfig config) {
super(api, config);
this.api = api;
this.config = config;
}
private void addOAuthParams(OAuthRequest request, Token token) {
request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));
}
private String getSignature(OAuthRequest request, Token token) {
String baseString = api.getBaseStringExtractor().extract(request);
String signature = api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());
return signature;
}
private void appendSignature(OAuthRequest request) {
for (Map.Entry<String, String> entry : request.getOauthParameters().entrySet()) {
request.addQuerystringParameter(entry.getKey(), entry.getValue());
}
}
#Override
public Token getRequestToken(RequestTuner tuner) {
OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());
addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
appendSignature(request);
Response response = request.send(tuner);
String body = response.getBody();
return api.getRequestTokenExtractor().extract(body);
}
}
TrakingApi class will be slightly different to create the an OAuth10aServiceForViagogo when calling createService :
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;
public class TradeKingAPI extends DefaultApi10a {
#override
public OAuthService createService(OAuthConfig config)
{
return new OAuth10aServiceForViagogo(this, config);
}
#Override
public Verb getRequestTokenVerb()
{
return Verb.GET;
}
#Override
public String getRequestTokenEndpoint() {
return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
}
#Override
public String getAccessTokenEndpoint() {
return "none";
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return "none";
}
}
Then your calling code will be the same :
OAuthService service = new ServiceBuilder()
.provider(TradeKingAPI.class)
.signatureType(QueryString)
.apiKey("My consumer key")
.apiSecret("My secret")
.scope("API.Public")
.build();
Token requestToken = service.getRequestToken();
//make your API calls
OAuthRequest request = new OAuthRequest(Verb.GET,
"http://api.viagogo.net/Public/Event/235");
service.signRequest(requestToken, request);
Response response = request.send();
System.out.println(response.getBody());
I didn't test all this code because I can't access consumer and secret key, but it should be close to what you need.
I'm assuming you're trying to get the access token (e.g you're calling SimpleOAuthAccessRequest). Scribe's OauthService has methods to handle this.
BUT ... if you're going to do it manually, here is what's wrong with your code - at least with what you've listed here. I'm assuming you've configured scribe correctly.
don't pass the consumer secret with your request, that is only for signing the request
you should use addOauthParameter vs addQueryStringParameter
you should use the Scribe constants
you need to sign the request (again, Scribe's OauthService has help method for signing request)
Here's your updated snippet of code.
UPDATE:
Have Scribe provide all the Oauth parameters for you
OAuthRequest request = new OAuthRequest(Verb.GET, ...
//since you're just passing Oauth parameters and nothing else,
//you can use signRequest will create Oauth Parameters for you
service.signRequest(OAuthConstants.EMPTY_TOKEN, request)
Response response = request.send()

Categories