Adding an object to skygear Social Login API - reactjs

I am using skygear social login. i want to append an object along with the request to the socialLogin api.The values in the object are a field in my UI application which needs to be saved in my db. The googleoauth 2.0 uses state to pass additional data in the query params . However I am not able to do so with skygear.
this is my code
function oauthlogin(provider,Cname,Cage){
return (
skygear.auth.loginOAuthProviderWithPopup('google',options:
{Cname,cage}).then(res=>{console.log(res})
)
}
I have tried options and state as it was given in the official documentation of Skygear.
Thanks in advance.

The skygear.auth.loginOAuthProviderWithPopup does accept options, but they are for auth only, which will not be saved as a field in the user profile.
Suggested way: save the fields via save record API after the login is successful (in the then part).
function oauthlogin(provider,Cname,Cage){
return (
skygear.auth.loginOAuthProviderWithPopup('google')
.then((user) => {
// save the user data here instead
user.Cname = Cname;
user.Cage = Cage;
skygear.publicDB.save(user).then(res => console.log(res));
})
)
}
Hope it helps!

Related

Save value to Firestore on Stripe successful payment status

I want to write the user free-input form data to Firestore based on them successfully completing the Stripe checkout through the PaymentElement. I was first trying to do so based on the stripe.confirmPayment method response, which did not work well. Any ideas or practical examples on how can this be implemented? I have also tried using Stripe Webhooks, but I am unsure how to pass the user free-input form data there. Can this generally be handled from the front end, or should I create Firebase function?
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: window.location.href
}
});

Nextjs - How Do I Store A JWT in The Client's Browser That Can Persist A Browser Restart

I am making an app that involves creating a JWT that the client must "remember" for at least 24 hours. I know that sounds strange but this app I'm building involves something called "Litprotocol" which does decentralized authorization. When a user logs in/registers, a JWT is created by a series of 3rd party servers, and the resulting JWT is valid for 24 hours. Since this JWT involves a somewhat intricate process, for efficiencies sake, I don't want to create a new JWT every time the user tries to login. The app is written in Nextjs and I tried to use the following code to attempt creating a persistently stored variable name "storedVal."
export default function Home(props: any) {
...
...
...
const [storedVal, setStoredVal] = useState(String);
function storePersistence() {
setStoredVal('I set this');
}
function printPersistence() {
console.log(storedVal);
}
return (
<>
<VStack>
<Heading as='h3'>Connect to see unity app</Heading>
{
!connected ? <Button variant='solid' onClick={connect}>Connect</Button> : <Text>Now you can click on protected path link at the bottom</Text>
}<br></br>
<Button variant='solid' onClick={storePersistence}>Store Persistence</Button>
<Button variant='solid' onClick={printPersistence}>Check Persistence</Button>
</VStack>
</>
)
}
The "Store Persistence" and "Check Persistence" buttons and functions are the relevant code. This doesn't work. As soon as I restart my browser, "storedVal" is cleared. So how can I make "storedVal" persist browser and possibly computer restarts?
General Idea/Mechanism for persisting data via localStorage/sessionStorage in client side.
Store it in localStorage when JWT is sent to client.
When user closes the site and open again that time fetch JWT from localStorage and check if it's valid or not and do the needful. Refer Blog for localstorage.
You can set JWT as follows localStorage.setItem("jwt", value) and fetch it localStorage.getItem("jwt")
You can use hooks/function provided by library/framework as well it does work on similar idea.
Aside from #GodWin's comment, you could also use this hook which I love: useLocalStorage. There's many variants of it and you can certainly write your own. It basically loads in a localStorage value into a hook given a key, for which you can provide a default value.
You can use it just like a useState:
function Home() {
const key = "local-jwt"
const defaultValue = null
const [jwt, setJWT] = useLocalStorage(key, defaultValue)
// use your jwt somewhere
return (
...
)
}

Django, Djoser social auth : State could not be found in server-side session data. status_code 400

I'm implementing an auth system with django and react. The two app run respectively on port 8000, 3000. I have implemented the authentication system using the Djoser package. This package uses some dependencies social_core and social_django. Everything seems to be configured ok. I click on login google button...I'm redirected to the google login page and then back to my front-end react app at port 3000 with the state and code parameters on the url.
At this point I'm posting those parameters to the backend. The backend trying to validate the state checking if the state key is present in the session storage using the code below from (social_core/backends/oauth.py)
def validate_state(self):
"""Validate state value. Raises exception on error, returns state
value if valid."""
if not self.STATE_PARAMETER and not self.REDIRECT_STATE:
return None
state = self.get_session_state()
request_state = self.get_request_state()
if not request_state:
raise AuthMissingParameter(self, 'state')
elif not state:
raise AuthStateMissing(self, 'state')
elif not constant_time_compare(request_state, state):
raise AuthStateForbidden(self)
else:
return state
At this point for some reasons the state session key is not there..and I receive an error saying that state cannot be found in session data ( error below )
{"error":["State could not be found in server-side session data."],"status_code":400}
I recap all the action I do:
Front-end request to backend to generate given the provider google-oauth2 a redirect url. With this action the url is generated also the state key is stored on session with a specific value ( google-oauth2_state ).
Front-end receive the url and redirect to google auth page.
Authentication with google and redirection back to the front-end with a state and code parameters on the url.
Front-end get the data form url and post data to back-end to verify that the state received is equal to the generated on the point (1).
For some reasons the state code is not persisted... Any ideas and help will be really appreciated.
Thanks to all.
ok so this is a common problem while you are working with social auth. I had the same problem for so many times.
The flow:
make a request to http://127.0.0.1:8000/auth/o/google-oauth2/?redirect_uri=http://localhost:3000/ (example)
you will get a authorization_url. if you notice in this authorization_url there is a state presented . this is the 'state of server side'.
now you need to click the authorization_url link.Then you will get the google auth page.After that you will be redirect to your redirect url with a state and a code. Remember this state should be the same state as the server side state .(2)
make post req to http://127.0.0.1:8000/auth/o/google-oauth2/?state=''&code=''.
if your states are not the same then you will get some issue.
everytime you wanna login , you need to make a request to http://127.0.0.1:8000/auth/o/google-oauth2/?redirect_uri=http://localhost:3000/
and then to http://127.0.0.1:8000/auth/o/google-oauth2/?state=''&code='' thus you will get the same state.
Without necessary detailed information, I can only tell 2 possible reasons:
You overrode backend with improper session operations(or the user was logged out before auth was finished).
Front-end used incorrect state parameter
You could test social login without front-end, let's say if you're trying to sign in with Google:
Enter the social login URL in browser, like domain.com:8000/login/google-oauth2/
Authorize
See if the page redirected to your default login page correctly
If yes, then probably you need to check your front-end code, and if no, then check your backend code.
At the end, if you're not so sensitive to the potential risk, you could also override GoogleOAuth2 class as following to disable state check:
from social_core.backends import google
class GoogleOAuth2(google.GoogleOAuth2):
STATE_PARAMETER = False
I think you may need some changes in you authorizing flow in step NO.3 and 4.
3.Authentication with google and redirection back to the front-end with a state and code parameters on the url.
4.Front-end get the data form url and post data to back-end to verify that the state received is equal to the generated on the point (1).
maybe you should redirect back to server side after google's authorization.
then at the server side, do the check! validate the state and code (maybe do more things).
then let server redirect to the front-end site you wanted to before.
for some reason, redirect to front-end directly will miss the param.. :-)
Finally, I reach a point where everything is working 200 percent fine, on local as well as production.
The issue was totally related to the cookies and sessions:
So rite answer typo is
make it look to your backend server as if the request is coming from localhost:8000, not localhost:3000,
means the backend domain should be the same always.
For making it possible you have two ways:
1: server should serve the build of the frontend then your frontend will always be on the same domain as the backend.
2: make a simple view in django and attach an empty template to it with only a script tag including logic to handle google auth. always when you click on signing with google move back you you're that view and handle the process and at the end when you get back your access token pass it to the frontend through params.
I used 2nd approach as this was appropriate for me.
what you need to do is just make a simple View and attach a template to it so on clicking on signIN with google that view get hit. and other process will be handled by the view and on your given URL access token will be moved.
View Code:
class GoogleCodeVerificationView(TemplateView):
permission_classes = []
template_name = 'social/google.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["redirect_uri"] = "{}://{}".format(
settings.SOCIAL_AUTH_PROTOCOL, settings.SOCIAL_AUTH_DOMAIN)
context['success_redirect_uri'] = "{}://{}".format(
settings.PASSWORD_RESET_PROTOCOL, settings.PASSWORD_RESET_DOMAIN)
return context
backend script code:
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
function redirectToClientSide(success_redirect_uri) {
window.location.replace(`${success_redirect_uri}/signin/`);
}
function getFormBoday(details) {
return Object.keys(details)
.map(
(key) =>
encodeURIComponent(key) + "=" + encodeURIComponent(details[key])
)
.join("&");
}
try {
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const redirect_uri = "{{redirect_uri|safe}}";
const success_redirect_uri = "{{success_redirect_uri|safe}}";
if (params.flag === "google") {
axios
.get(
`/api/accounts/auth/o/google-oauth2/?redirect_uri=${redirect_uri}/api/accounts/google`
)
.then((res) => {
window.location.replace(res.data.authorization_url);
})
.catch((errors) => {
redirectToClientSide(success_redirect_uri);
});
} else if (params.state && params.code && !params.flag) {
const details = {
state: params.state,
code: params.code,
};
const formBody = getFormBoday(details);
// axios.defaults.withCredentials = true;
axios
.post(`/api/accounts/auth/o/google-oauth2/?${formBody}`)
.then((res) => {
const formBody = getFormBoday(res.data);
window.location.replace(
`${success_redirect_uri}/google/?${formBody}`
);
})
.catch((errors) => {
redirectToClientSide(success_redirect_uri);
});
} else {
redirectToClientSide(success_redirect_uri);
}
} catch {
redirectToClientSide(success_redirect_uri);
}
</script>
</body>

Create user profile with user choice on firestore using redirect

I am creating a site using react-redux-firebase, and when a user logs in with facebook I want to create a profile that stores a user choice. I know how to define what to store with the profileFactory, but I don't know how to pass dynamic data coming from the user. In my case I want to save the users' language. My configuration is similar to this:
const config = {
userProfile: 'users', // where profiles are stored in database
profileFactory: (userData, profileData) => { // how profiles are stored in database
const { user } = userData
return {
language: [i need to put here what the user chose]
email: user.email
}
}
}
The configuration was based on this recipe.
When logging in I'm using type redirect.
await firebase.login({
provider: 'facebook',
type: 'redirect'
})
How could I save the user choice when the user is created?
To solve the user custom fields I'm creating a user when the redirect comes back from facebook.
I'm still not totally sure this is the best way to do it. Seems odd that I can define a profileFactory but can't pass user custom fields in some way.

Referring page to app

I have an application added to several fan pages.
Ideally, the application should work custom depending on the referring page.
How can I detect which page referred to the app.
Developing a Facebook Iframe app, Using PHP.
(Question posted on Facebook's dev forum as well:
http://forum.developers.facebook.net/viewtopic.php?id=108409)
Thx,
Oren.
As explained in the Page Tab Tutorial
When a user selects your Page Tab, you will received the signed_request parameter with one additional parameter, page. This parameter contains a JSON object with an id (the page id of the current page), admin (if the user is a admin of the page), and liked (if the user has liked the page). As with a Canvas Page, you will not receive all the user information accessible to your app in the signed_request until the user authorizes your app.
With the http referer, you will have the the Facebook proxy url.
In your case, I think you have to use the id of the page (passed in the signed request).
The following PHP snippet will output the signed_request received on the page tab. You will find the page ID needed in your case.
<?php
$appsecret = 'Your App Secret';
$signed_request = $_REQUEST['signed_request'];
$request = $_REQUEST;
$signed_request = parse_signed_request($signed_request, $appsecret);
print_r($signed_request);
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
?>
Using the new php-sdk, there is a quicker way to find out the referring page. $facebook->getSignedRequest() will return an array with the signed request, authorization token, page and user basic info.

Resources