I have been looking for some documentation around how to do OAuth in the Play framework (version 2.2.2) and I can't really find anything. I read in one place that it has been deprecated but I haven't been able to find anything about this either. Does anyone know? I want to connect to the Twitter API and make some requests for data in my application.
You can find examples of OAuth with Play Framework on these open source projects:
securesocial
play-silhouette
play-authenticate
It's supported and actually pretty straight forward.
Here's an OAuth authorization example directly from the Play Docs:
object Twitter extends Controller {
val KEY = ConsumerKey("xxxxx", "xxxxx")
val TWITTER = OAuth(ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize", KEY),
false)
def authenticate = Action { request =>
request.queryString.get("oauth_verifier").flatMap(_.headOption).map { verifier =>
val tokenPair = sessionTokenPair(request).get
// We got the verifier; now get the access token, store it and back to index
TWITTER.retrieveAccessToken(tokenPair, verifier) match {
case Right(t) => {
// We received the authorized tokens in the OAuth object - store it before we proceed
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
}
}.getOrElse(
TWITTER.retrieveRequestToken("http://localhost:9000/auth") match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
})
}
def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
for {
token <- request.session.get("token")
secret <- request.session.get("secret")
} yield {
RequestToken(token, secret)
}
}
}
If you want to sign request, you can do it like this:
WS.url(s"https://api.twitter.com/1.1/account/verify_credentials.json")
.sign(OAuthCalculator(Key, RequestToken(token, tokenSecret)))
.get
Please note that the above is for OAuth 1.0. OAuth2 is very easy to implement without a dedicated library that why the Play folks left it out.
Related
I'm trying to create a group room using Twilio REST API, but i am facing a crash:
Process: com.example.twilioroom, PID: 25401
java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar!classes2.dex)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:151)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.getSystemSocketFactory(SSLConnectionSocketFactory)
Here is my code where i'm trying to verify hostname:
Twilio.init(multiAccountSID,multiAccountAuthToken)
val httpClientBuilder = HttpClientBuilder.create()
httpClientBuilder.setSSLHostnameVerifier(object : HostnameVerifier{
override fun verify(hostname: String?, session: SSLSession?): Boolean {
certs = try {
session!!.peerCertificates
} catch (e: SSLException) {
return false
}
val x509: X509Certificate = certs[0] as X509Certificate
val hostName = hostname!!.trim().toLowerCase(Locale.ENGLISH)
val firstCn: String = getFirstCn(x509)
if (Pattern.matches(hostName, firstCn)) {
return true
}
for (cn in getDNSSubjectAlts(x509)) {
if (Pattern.matches(hostName, cn!!)) {
return true
}
}
return true
}
})
val verifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
val sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory()
httpClientBuilder.setSSLSocketFactory(sslSocketFactory)
httpClientBuilder.build()
val networkHttpClient = NetworkHttpClient(httpClientBuilder)
val twilioRestClient = TwilioRestClient.Builder(multiAccountSID,multiAccountAuthToken).httpClient(networkHttpClient).build()
Log.d("networkHttpClient", "getAccessToken: "+networkHttpClient.lastResponse.statusCode)
but i'm getting error on:
val sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory()
Can someone help me what I'm doing wrong?
The Twilio Java library is not built to be used in an Android application. This is because the Twilio library requires your account credentials in order to make requests to the API and if your application is handling those credentials a malicious user could decompile the application, extract the credentials and use them to abuse your account.
Instead, you should make the requests to the Twilio API from a server side application, where you can keep the API credentials safe, and trigger that request from your application.
Here is more about why you should not make API requests from your Android application and an example how to build a server side application that can make these requests for your application (the example is to send an SMS, but you can switch that out for using the Verify API).
I'm trying to use the egg_mode crate to retrieve a stream of tweets as per the example here but with just a slight difference in the way I input my token.
#[tokio::main]
async fn main() {
let con_token = egg_mode::KeyPair::new(CONSUMER_KEY, CONSUMER_SECRET);
println!("Live streaming tweets...");
println!("Ctrl-C to quit\n");
let stream = egg_mode::stream::filter()
.track(&["rustlang"])
.start(&Token::Bearer(BEARERTOKEN.to_string()))
.try_for_each(|m| {
if let StreamMessage::Tweet(tweet) = m {
println!("{}\n{}",tweet.created_at,tweet.text);
} else {
println!("{:?}",m);
}
futures::future::ok(())
});
if let Err(e) = stream.await {
println!("Stream error: {}", e);
println!("Disconnected")
}
}
However I keep getting a 401 unauthorized error.
Using the same bearer token, I am able to retrieve tweets with no problem using egg_mode::tweet::user_timeline as per the example here.
What could be the problem?
It has succeeded after passing the Access variant of the Token enum instead of the Bearer variant.
I'm trying to use Google Oauth to access Google Analytics Datas.
It's works fine except with token. The token expires after an hour and I don't know how to refresh it. There a line where there's "For simplicity of the example we only store the accessToken. If it expires use the refreshToken to get a fresh one" but I don't know how to…
Here's my code
$client_id = 'xxxxxxxxxx.apps.googleusercontent.com';
// From the APIs console
$client_secret = 'xxxxxxxxxxxxx';
// Url to your this page, must match the one in the APIs console
$redirect_uri = 'mylocalurl.php';
session_start();
include('GoogleAnalyticsAPI.class.php');
$ga = new GoogleAnalyticsAPI();
$ga->auth->setClientId($client_id);
$ga->auth->setClientSecret($client_secret);
$ga->auth->setRedirectUri($redirect_uri);
if (isset($_GET['force_oauth'])) {
$_SESSION['oauth_access_token'] = null;
}
/*
* Step 1: Check if we have an oAuth access token in our session
* If we've got $_GET['code'], move to the next step
*/
if (!isset($_SESSION['oauth_access_token']) && !isset($_GET['code'])) {
// Go get the url of the authentication page, redirect the client and go get that token!
$url = $ga->auth->buildAuthUrl();
header("Location: ".$url);
}
/*
* Step 2: Returning from the Google oAuth page, the access token should be in $_GET['code']
*/
if (!isset($_SESSION['oauth_access_token']) && isset($_GET['code'])) {
$auth = $ga->auth->getAccessToken($_GET['code']);
if ($auth['http_code'] == 200) {
$accessToken = $auth['access_token'];
$refreshToken = $auth['refresh_token'];
$tokenExpires = $auth['expires_in'];
$tokenCreated = time();
// For simplicity of the example we only store the accessToken
// If it expires use the refreshToken to get a fresh one
$_SESSION['oauth_access_token'] = $accessToken;
} else {
die("Sorry, something wend wrong retrieving the oAuth tokens");
}
}
Thanks
I am not sure of the details of doing this in PHP but there is an end point to request against for refreshing the access token.
The API end point is https://accounts.google.com/o/oauth2/token and the body of request should be something like
{
'refresh_token' => your_stored_refresh_token,
'client_id' => ENV['CLIENT_ID'],
'client_secret' => ENV['CLIENT_SECRET'],
'grant_type' => 'refresh_token'
}
If successful that request will return a fresh access token.
Good evening:
I am implementing two-legged OAuth 2.0 and I wanted to know how to generate a "random" and unique refresh_token.
The user will send a refresh_token, this token will be look up in the database to get the user related to this token. How could be a token generate in order to prevent collisions in the database?
Thanks in advance
ThePHPLeague OAuth2 library uses the helper class to generate random keys.
If you are using PHP look at : openssl_random_pseudo_bytes()
https://github.com/thephpleague/oauth2-server/blob/master/src/Util/SecureKey.php
Specifically:
class DefaultAlgorithm implements KeyAlgorithmInterface
{
public function generate($len = 40)
{
$stripped = '';
do {
$bytes = openssl_random_pseudo_bytes($len, $strong);
// We want to stop execution if the key fails because, well, that is bad.
if ($bytes === false || $strong === false) {
throw new \Exception('Error Generating Key');
}
$stripped .= str_replace(['/', '+', '='], '', base64_encode($bytes));
} while (strlen($stripped) < $len);
return substr($stripped, 0, $len);
}
}
I'm storing the oauth info from Twitter in a Flash Cookie after the user goes though the oauth process. Twitter says that this token should only expire if Twitter or the user revokes the app's access.
Is there a call I can make to Twitter to verify that my stored token has not been revoked?
All API methods that require authentication will fail if the access token expires. However the specific method to verify who the user is and that the access token is still valid is GET account/verify_credentials
This question may be old, but this one is for the googlers (like myself).
Here is the call to twitter using Hammock:
RestClient rc = new RestClient {Method = WebMethod.Get};
RestRequest rr = new RestRequest();
rr.Path = "https://api.twitter.com/1/account/verify_credentials.json";
rc.Credentials = new OAuthCredentials
{
ConsumerKey = /* put your key here */,
ConsumerSecret = /* put your secret here */,
Token = /* user access token */,
TokenSecret = /* user access secret */,
Type = OAuthType.AccessToken
};
rc.BeginRequest(rr, IsTokenValid);
Here is the response:
public void IsTokenValid(RestRequest request, RestResponse response, object userState)
{
if(response.StatusCode == HttpStatusCode.OK)
{
var user = userState;
Helper.SaveSetting(Constants.TwitterAccess, user);
}
else
{
Dispatcher.BeginInvoke(() => MessageBox.Show("This application is no longer authenticated "))
}
}
I always borrow solutions from SO, this is my first attempt at giving back, albeit quite late to the question.
When debugging manually:
curl \
--insecure https://api.twitter.com/1/account/verify_credentials.json?oauth_access_token=YOUR_TOKEN
I am using TwitterOAuth API and here is the code based on the accepted answer.
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $twitter_oauth_token, $twitter_oauth_secret);
$content = $connection->get("account/verify_credentials");
if($connection->getLastHttpCode() == 200):
// Connection works fine.
else:
// Not working
endif;