Facebook graph authenticate client side and server side simultaneously? - ruby-on-rails

Here is what I am trying to do using facebook graph on my rails site:
user client-side flow to get user permissions and authenticate user w/ facebook
send the access token received on the client-side to my server for additional processing from the server side
When I try to do this, I get an error from facebook saying I cannot authenticate the server. I am using the same token to do this that was given to me on the client side. Is there any way to authenticate the server without having the user log in using the server-side process?

try something like this in your JavaScript:
FB.login(function(response) {
if (response.session) {
location.href = '#{authenticate_path}?access_token=' + escape(response.session.access_token);
}
}, {perms: 'offline_access'});
You can then access facebook via the OAuth2 gem with the given access token:
client = OAuth2::Client.new(<app_id>, <app_secret>, :site => 'https://graph.facebook.com')
token = OAuth2::AccessToken.new client, params[:access_token]
token.get('/me')

Related

Invalid Authorization Code auth_code_not_found in OAuth2

Hi guy I have a simple diagram to explain what I to achieve
first want to authenticate OAuth with mobile because mobile cant receive a callback from auth server so I need to create new simple node server for handle authentication code and get real token everything just fine until getting real token I already send code
you will see URL that console log print
already attach code in URL
I dint know issue come from guess because different referer who getting and obtain code
because I try to use only server:9000 getting and obtain access token is work
we dont need server for obtain token just only external browser and deeplink
here solove workflow
native trigger external browser
browser send authentication request to auth server
authserver send authorization back to browser
browser trigger some address that associate to app with deeplinking also passs auth code with query param
native capture auth token then send code to auth server for obtain access_token
auth server send access token back to native 
native store access token in secure storage like keychain and shared preference 

Google API OAuth 2.0 get user permission on mobile device, use on server side API

I have a mobile app and I want to add events on the user's google calendar from my server. I've added the consent flow on iOs and I get an idToken from the response. I can also get an accessToken using getTokens on the client. However I am not able to use these in order to get an appropriate refresh token on the server so I can call the Calendar API at a later stage. For a web app it requires a client secret. The ios client does not have a secret and when I use my web client id and secret I get insufficientPermissions: Insufficient Permission: Request had insufficient authentication scopes. .
To clarify, my steps are:
get consent and idToken on the phone
send idToken to the server
use idToken to get refresh token on the server (this is where things fall apart)
use refresh token to create events on the user's calendar
Here's my ios React Native code:
signInWithGoogle() {
GoogleSignin.configure({scopes: ['https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.events']});
GoogleSignin.signIn()
.then(result => {
// idToken
console.log(result);
GoogleSignin.getTokens()
.then(tokens => {
//this gets me an accessToken
console.log(tokens);
})
}).catch(error => {
console.log('google auth error: ', error);
});
}
And my server side code:
secrets = Google::APIClient::ClientSecrets.new({
"web" => {
"refresh_token" => ENV['GOOGLE_REFRESH_TOKEN'],
"client_id" => ENV["GOOGLE_CLIENT_ID"],
"client_secret" => ENV["GOOGLE_CLIENT_SECRET"]
}
})
auth_code = idToken_from_client
auth_client = secrets.to_authorization
auth_client.update!(scope: 'https://www.googleapis.com/auth/calendar.events')
auth_client.code = auth_code
auth_client.fetch_access_token!
I know the server code doesn't make sense because I already have an access token, however I need a refresh token. I will need to create events for the user as long as they use the app and access tokens expire. And this is what they recommended for getting a refresh token in the server side auth docs: https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code
Thanks for your help!
What I ended up doing is using the auth flow for installed apps opening a system browser window, using the web client id and secret. I use the redirect uri pointing to my server endpoint where I use the google-api-client to obtain a refresh and access token with the provided code.
ReactNative code:
const scope = 'scope=the_google_scope';
const redirect = 'redirect_uri=redirect_for_google_auth'; // Your serverside endpoint
const url = `https://accounts.google.com/o/oauth2/v2/auth?${scope}&prompt=consent&access_type=offline&response_type=code&${redirect}&client_id=${googleClientID}`
Linking.openURL(url);
Rails code:
require "google/api_client/client_secrets.rb"
...
secrets = Google::APIClient::ClientSecrets.new({
web: {
client_id: googleClientID, # Same one used on the client
client_secret: googleClientSecret,
grant_type: "authorization_code",
redirect_uri: "redirect_for_google_auth"
}
})
auth_client = secrets.to_authorization
auth_client.code = code_retrieved_from_google
auth_result = auth_client.fetch_access_token!
Hopes this helps other people with this scenario.
Because you are following the wrong flow. When you are following an installed app flow you can reach the access_token and referesh_token from the mobile side but it doesn't work on the server-side. So, you need to pursue the web flow instead which your mobile app just brings up the google oauth2 authorization page and performs sending authorization code toward server-side and this is server-side responsibility to exchange that code to access_token and refresh_token using the web flow app credentials which are created in the google developer console.
Here I've posted a more comprehensive answer to solve this issue.

What is the redirect_uri in Alexa Skill Activation API?

Background
I'm implementing Alexa's App-to-App Account Linking Flow, and I'm stuck on Step 6 - enabling the skill using Alexa's Skill Activation API.
Concretely, I am not sure what value to supply to the redirect_uri POST field. In the docs, the following description is provided:
The redirect_uri parameter that was included in the authorization request to your OAuth 2.0 server to obtain the user's authorization code. This enables Amazon to retrieve access tokens from your token server. This URL must be opaque to Amazon.
My understanding is that Alexa wants to exchange an existing authorization code for an access token, but I don't know how Alexa is trying to accomplish this "under the hood" and my current approach throws a 400 error.
Error Message
[status] 400
[response] {"message":"Could not contact provider of account linking credentials"}
Notes
My app uses Firebase authentication, and creates accounts for users via federated login with Google and Facebook. Thus, Google and Facebook redirect back to my native app (React Native).
I do not have a universal link; instead in my account-linking flow,
the Alexa app redirects users to an html page that redirects to my app using its custom schema.
When a user signs into my app from Alexa, Alexa redirects them from my login page back to the Alexa app. In this case, the Alexa universal link is the redirect url.
When a user signs into Alexa from my app (app-to-app linking), The Alexa app redirects them to my app. My app is the redirect url.
I have tried using my app's [faux] "universal link" as the redirect url, to no avail. There are no other redirects in my login flows. What is this url supposed to be?
NB: I have a endpoint for exchanging an auth_code for an access_token. The token is returned in the body; there's no redirect with the access_token appended to the redirect_url.
Example Skill Activation (my React Native app):
async enableSkill() {
try {
let response = await fetch(`https://api.amazonalexa.com/v1/users/~current/skills/${this.skillId}/enablement`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.alexaAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
stage: 'development', // or live
accountLinkRequest: {
redirectUri: Linking.makeUrl(), // <--- unsure
authCode: this.myAppAuthCode, // <-- auth code from my system, not Alexa's
type: "AUTH_CODE"
}
})
});
return response.json();
} catch (err) {
throw new Error(err);
}
}
I think it is not possible to use different OAuth Server like Google and Facebook together. I am not sure if it is possible to use firebase as OAuth Server.
In the account linking tab of the skill, you have to enter the details of the OAuth server you want to use and in the accountLinkRequest you must enter the redirectUri which you used for the OAuth Login with this server.
When you have your own OAuth server make sure it is running on port 443. It took me hours to find out that it is not working with Port 3000 which my Node.js backend used.
According to the developer documentation The redirect_uri you are asking about is a parameter that was included in the authorization request to your OAuth 2.0 server to obtain the user's authorization code. This enables Amazon to retrieve access tokens from your token server. You must set this URL in the developer console of your skill like that:

How do I Implement twitter Oauth into my Google chrome extension

I figured out how to get the sign in button and redirect through php code. BUT, Chrome Dev only allows client side code. How do I get the log in with twitter with client side code for my Chrome app?
is there a way to run php code for a chrome app?
Here is another alternative to CodeBird for authenticating a twitter user in a Chrome extension.
The key with this approach is to provide Twitter with a legitimate domain for the callback URL for your app. Then, use content scripts to inject a script onto that same domain. That script will parse the query string of the URL to get the tokens and send those tokens in a message to your extension's background script. Your background script will take the tokens and then perform the third leg of the oauth process, which will finally get you the oauth token and oauth token secret.
Here is a brief example:
in your manifest.json, make sure your content script matches the same domain that you put in your twitter app settings callback URL:
"content_scripts": [{
"matches": ["https://andyjiang.com/*"],
"js": ["js/session.js"]
}]
Then, in your js/session.js file, have this sort of logic:
chrome.runtime.sendMessage({type: 'auth', session:
window.location.search.substr(1)}, function(response) {
window.open('', '_self', '');
window.close();
});
In your background script, have some logic that listens for the message, gets the token, and uses Twitter's API for the third leg of the oauth process to finally get the oauth token and oauth token secret, which you can then save in localStorage or chrome.storage.
Here is sample code of the logic:
https://github.com/lambtron/chrome-extension-twitter-oauth-example
Hope that helps!
You can use the Chrome Identity API for this. Check out Non-Google account authentication for simple instructions on making a request using the launchWebAuthFlow API function.
Previously, there were client side libraries for implementing the OAuth flow, such as oauth2-extensions described here, but thankfully this is not required anymore .
Update
I've been playing around trying to get an example working for Twitter, but haven't quite got there. It appears that Twitter doesn't have an API endpoint that matches the OAuth2 URL that is expected. I think in the case of Twitter, you may have to use OAuth 1.0a instead, which would require a library after all. I found one called CodeBird. I will try and investigate further though.
Example using Chrome Identity API to Authorise Instagram
You need to register the client to your provider with https://abcdefghijklmnopqrstuvwxyzabcdef.chromiumapp.org/intagram_cb, where 'abcdefghijklmnopqrstuvwxyzabcdef' is replaced with your extension ID and intagram_cb is name for a path to be able to distinguish between other providers you wish to authenticate with within the extension. If you only have one, then you can omit it.
Add provider to the permissions property in the manifest.json file:
"permissions": [
"*://*.instagram.com/*"
]
Get access token. You obtain the client_id token from your provider account:
var redirect_uri = chrome.identity.getRedirectURL("intagram_cb");
var client_id = "123456789012345";
var auth_url = "https://instagram.com/oauth/authorize/?" +
"client_id=" + client_id + "&" +
"response_type=token&" +
"redirect_uri=" + encodeURIComponent(redirect_uri);
chrome.identity.launchWebAuthFlow({'url':auth_url, 'interactive': true},
function(redirect_url) {
// extract the token from this url and use it for future requests
var accessToken = redirect_url.substring(redirect_url.indexOf("=") + 1);
}
});

Javamail OAuth authentication failed when connecting to Exchange imap using OAuth token

I'm trying to connect to Exchange using Javamail and OAuth. I'm using Javamail 1.5.3 and I referred to this.
1) The exchange account that I'm trying to connect to is within an org domain. I know that my OAuth token is valid since I'm able to make a Rest api request to https://outlook.office.com/api/v2.0/me to get the user profile using the token. My code looks like this -
Properties props = new Properties();
props.put("mail.imap.ssl.enable", "true);
props.put("mail.imap.sasl.enable", "true");
props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.login.disable", "true");
props.put("mail.imap.auth.plain.disable", "true");
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
store.connect("imap-mail.outlook.com", "xxx#org.com", OAUTH_TOKEN);
I get (javax.mail.AuthenticationFailedException) javax.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] OAuth authentication failed
2) When I connect to an xxx#outlook.com account, I get 500:Internal Server Error and I'm not able to make the api request above to fetch the user profile using the OAuth token I received.

Resources