Been facing this issue
"You have created a new client application that uses libraries for user authentication or authorization that will soon be deprecated. New clients must use the new libraries instead; existing clients must also migrate before these libraries are deprecated. See the Migration Guide for more information."
How to sign in with google now if they have block client ID for new users
as google will deprecate their old sign in library
https://developers.googleblog.com/2021/08/gsi-jsweb-deprecation.html
you can now implement their new google service identity SDK https://developers.google.com/identity/gsi/web
or if you are using react, I made a small package https://www.npmjs.com/package/#react-oauth/google
it is using the new SDK
I was having this issue and solved it using this answer
import React, { useEffect } from 'react';
import { GoogleLogin, GoogleLogout } from 'react-google-login';
import env from 'react-dotenv';
import { gapi } from 'gapi- script';
function AuthPage() {
useEffect(() => {
function start() {
gapi.client.init({
clientId: env.REACT_PUBLIC_GOOGLE_CLIENT_ID,
scope: 'email',
});
}
gapi.load('client:auth2', start);
}, []);
// **you can access the token like this**
// const accessToken = gapi.auth.getToken().access_token;
// console.log(accessToken);
const onSuccess = response => {
console.log('SUCCESS', response);
};
const onFailure = response => {
console.log('FAILED', response);
};
const onLogoutSuccess = () => {
console.log('SUCESS LOG OUT');
};
return (
<div>
<GoogleLogin
clientId={env.REACT_PUBLIC_GOOGLE_CLIENT_ID}
onSuccess={onSuccess}
onFailure={onFailure}
/>
<GoogleLogout
clientId={env.REACT_PUBLIC_GOOGLE_CLIENT_ID}
onLogoutSuccess={onLogoutSuccess}
/>
</div>
);
}
export default AuthPage;
I've faced the same issue, like you.
This is how I solved it in my React Application. https://stackoverflow.com/a/72944782/15145736
it will solve the problem
For angular developers,
a repository with an example of how to use the new google sign in:
https://github.com/ShemiNechmad/GoogleSignInAngular
Check the readme.md file for instructions.
Related
We operate bots by combining Firebase and Slack/bolt.
I currently use functions.config()to manage my Slack tokens and secrets, but would like to migrate to using Secret Manager.
https://firebase.google.com/docs/functions/config-env#secret-manager
boltapp.js
const functions = require("firebase-functions");
const { App, ExpressReceiver, subtype } = require("#slack/bolt");
const config = functions.config();
const expressReceiver = new ExpressReceiver({
signingSecret: process.env.SLACK_SECRET,
endpoints: "/events",
processBeforeResponse: true,
});
const app = new App({
receiver: expressReceiver,
token: process.env.SLACK_TOKEN
});
app.error(error => { console.error(error) });
app.use(async ({ client, payload, context, next }) => {
console.info('It\'s payload', JSON.stringify(payload))
if (!context?.retryNum) {
await next();
} else {
console.debug('app.use.context', context);
}
});
//**bot processing**//
// https://{your domain}.cloudfunctions.net/slack/events
module.exports = functions
.runWith({ secrets: ["SLACK_TOKEN","SLACK_SECRET"] })
.https.onRequest(expressReceiver.app);
But when I rewrote it for migration, I got the following error.
Is there a way to rewrite the code while avoiding this error?
Failed to load function definition from source: FirebaseError: Failed to load function definition from source: Failed to generate manifest from function source: Error: Apps used in a single workspace can be initialized with a token. Apps used in many workspaces should be initialized with oauth installer options or authorize.
Since you have not provided a token or authorize, you might be missing one or more required oauth installer options. See https://slack.dev/bolt-js/concepts#authenticating-oauth for these required fields.
I've been trying to configure my Application with an existing Backend as suggested in this link, from the amplifyConfig.ts configuration file (see below)
Then, I import the configuration file in the Login.tsx page and invoke it by passing Amplify.configure(currentConfig)
The first unexpected behavior is that, regardless I define authenticationFlowType: 'CUSTOM_AUTH', when I call the Auth.Signup method, the authenticationFlowType is still defined as "USR_SRP_AUTH".
Second, whenever I change the AmplifyConfig.ts file, I have to clear all the browsing data in order for those changes to work.
This behavior suggests me I'm doing something wrong, I understand I can deal this via cli, however I would prefer to handle this via code.
Thanks a lot!!
amplifyConfig.ts:
import Amplify, { Auth } from 'aws-amplify';
Amplify.configure({
Auth: {
// REQUIRED - Amazon Cognito Region
region: 'XX-XXXX-X',
// OPTIONAL - Amazon Cognito User Pool ID
userPoolId: 'XX-XXXX-X_abcd1234',
// OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
authenticationFlowType: 'CUSTOM_AUTH',
}
}
});
// You can get the current config object
const currentConfig = Auth.configure();
Login.tsx:
import Amplify, { Auth } from 'aws-amplify';
import currentConfig from '../../services/amplifyConfig';
export function LoginMenu() {
Amplify.configure(currentConfig);
// redundant configuration of authenticationFlowType
Auth.configure({
authenticationFlowType: 'CUSTOM_AUTH',
});
async function onSignup(event: FormEvent) {
event?.preventDefault();
try {
const { user } = await Auth.signUp(UserData);
console.log(user);
} catch (error) {
console.log('error signing up:', error);
}
}
}
I am trying to redirect to stripe checkout using a click event that calls the payStripe function
<button #click="payStripe" class="btn btn-primary" type="button">Place Order</button>
I have imported stripe into my Vue component like so;
import { loadStripe } from "#stripe/stripe-js";
const stripe = loadStripe('MY-KEY');
I am using Firebase cloud functions and axois to fetch the session and store this to a data property, this works fine.
But, the payStripe method, when called, gives the following error;
Error in v-on handler: "TypeError: stripe.redirectToCheckout is not a function"
Here is the function i am using which, from all accounts is similar to the Stripe API docs;
data() {
return {
sessionId: null,
}
},
methods: {
//This function sends us to the stripe checkout
payStripe() {
stripe.redirectToCheckout({
sessionId: this.sessionId
})
.then(function(result) {
console.log(result);
}).catch(function(error) {
console.log(error);
});
}
},
I had original issues with babel-core, so i updated to #babel/core to get rid of rest operator issues when compling code, but faced with this new issue. Any advice would be great. Thank you
According to the documentation here, loadStripe returns a promise that you must wait to resolve.
Try something like
import { loadStripe } from "#stripe/stripe-js"
const stripeInit = loadStripe('MY-KEY') // returns a promise
and when you want to use stripe
methods: {
//This function sends us to the stripe checkout
payStripe() {
// wait for the promise to resolve first
stripeInit.then(stripe => {
stripe.redirectToCheckout({
sessionId: this.sessionId
}).then(function(result) {
console.log(result);
}).catch(function(error) {
console.error(error);
});
})
}
}
Using Laravel Homestead as a vm, I turned ssl: true in Homestead.yaml, and entered https://site.test manually in the URL. I didn't get a valid https certificate, but the vue-stripe components load and it works
I'm trying to figure out an appropriate way of doing authentication, which I know is a touchy subject on the GitHub issue page.
My authentication is simple. I store a JWT token in the session. I send it to a different server for approval. If I get back true, we keep going, if I get back false, it clears the session and puts sends them to the main page.
In my server.js file I have the following (note- I am using the example from nextjs learn and just adding isAuthenticated):
function isAuthenticated(req, res, next) {
//checks go here
//if (req.user.authenticated)
// return next();
// IF A USER ISN'T LOGGED IN, THEN REDIRECT THEM SOMEWHERE
res.redirect('/');
}
server.get('/p/:id', isAuthenticated, (req, res) => {
const actualPage = '/post'
const queryParams = { id: req.params.id }
app.render(req, res, actualPage, queryParams)
})
This works as designed. If I refresh the page /p/123, it will redirect to the /. However, if I go there via a next/link href, it doesn't. Which I believe is because it's not using express at this point but next's custom routing.
Is there a way I can bake in a check for every single next/link that doesn't go through express so that I can make sure the user is logged in?
Tim from the next chat helped me solve this. Solution can be found here but I will quote him so you all can see:
You can do the check in _app.js getInitialProps and redirect like this
Example of how to use it
_app.js documentation
I've also created an example skeleton template you can take a look at.
--
EDIT July 2021 - WARNING: This is an outdated solution and has not been confirmed to work with the latest versions of next.js. Use skeleton template at your own risk.
Edit: Updated answer for Next 12.2+
Note: The below contents is copied from the official blog post since SO generally discourages links that can become stale/dead over time
https://nextjs.org/blog/next-12-2#middleware-stable
Middleware is now stable in 12.2 and has an improved API based on feedback from users.
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
// If the incoming request has the "beta" cookie
// then we'll rewrite the request to /beta
export function middleware(req: NextRequest) {
const isInBeta = JSON.parse(req.cookies.get('beta') || 'false');
req.nextUrl.pathname = isInBeta ? '/beta' : '/';
return NextResponse.rewrite(req.nextUrl);
}
// Supports both a single value or an array of matches
export const config = {
matcher: '/',
};
Migration guide
https://nextjs.org/docs/messages/middleware-upgrade-guide
Breaking changes
No Nested Middleware
No Response Body
Cookies API Revamped
New User-Agent Helper
No More Page Match Data
Executing Middleware on Internal Next.js Requests
How to upgrade
You should declare one single Middleware file in your application, which should be located next to the pages directory and named without an _ prefix. Your Middleware file can still have either a .ts or .js extension.
Middleware will be invoked for every route in the app, and a custom matcher can be used to define matching filters. The following is an example for a Middleware that triggers for /about/* and /dashboard/:path*, the custom matcher is defined in an exported config object:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
return NextResponse.rewrite(new URL('/about-2', request.url))
}
// Supports both a single string value or an array of matchers
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
Edit: Outdated answer for next > 12 and < 12.2
With the release of Next.js 12, there's now beta support for middleware using Vercel Edge Functions.
https://nextjs.org/blog/next-12#introducing-middleware
Middleware uses a strict runtime that supports standard Web APIs like fetch. > This works out of the box using next start, as well as on Edge platforms like Vercel, which use Edge Functions.
To use Middleware in Next.js, you can create a file pages/_middleware.js. In this example, we use the standard Web API Response (MDN):
// pages/_middleware.js
export function middleware(req, ev) {
return new Response('Hello, world!')
}
JWT Authentication example
https://github.com/vercel/examples/tree/main/edge-functions/jwt-authentication
in next.config.js:
const withTM = require('#vercel/edge-functions-ui/transpile')()
module.exports = withTM()
in pages/_middleware.js:
import { NextRequest, NextResponse } from 'next/server'
import { setUserCookie } from '#lib/auth'
export function middleware(req: NextRequest) {
// Add the user token to the response
return setUserCookie(req, NextResponse.next())
}
in pages/api/_middleware.js:
import type { NextRequest } from 'next/server'
import { nanoid } from 'nanoid'
import { verifyAuth } from '#lib/auth'
import { jsonResponse } from '#lib/utils'
export async function middleware(req: NextRequest) {
const url = req.nextUrl
if (url.searchParams.has('edge')) {
const resOrPayload = await verifyAuth(req)
return resOrPayload instanceof Response
? resOrPayload
: jsonResponse(200, { nanoid: nanoid(), jwtID: resOrPayload.jti })
}
}
in pages/api/index.js:
import type { NextApiRequest, NextApiResponse } from 'next'
import { verify, JwtPayload } from 'jsonwebtoken'
import { nanoid } from 'nanoid'
import { USER_TOKEN, JWT_SECRET_KEY } from '#lib/constants'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'GET') {
return res.status(405).json({
error: { message: 'Method not allowed' },
})
}
try {
const token = req.cookies[USER_TOKEN]
const payload = verify(token, JWT_SECRET_KEY) as JwtPayload
res.status(200).json({ nanoid: nanoid(), jwtID: payload.jti })
} catch (err) {
res.status(401).json({ error: { message: 'Your token has expired.' } })
}
}
There is no middleware for no API routes in NextJS, but there are HOCs, which you can use to connect to db - select the user, etc:
https://hoangvvo.com/blog/nextjs-middleware
I develop a react-native (expo) mobile app and try to sign in with a google account to firebase, but I get an error:
"auth/operation-not-supported-in-this-enviroment. This operation is not supported in the enviroment this application is running on. "location.protocol" must be http, https or chrome-extension and web storage must be enabled"
Code:
loginGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
return true;
}).catch(function(error) {
alert(error.code + '\n' +
error.message + '\n' +
error.email + '\n' +
error.credential);
return false;
});
}
signInWithPopup is not supported in react-native. You will need to use a third party OAuth library to get the OAuth ID token or access token and then sign in with Firebase:
const cred = firebase.auth.GoogleAuthProvider.credential(googleIdToken, googleAccessToken);
firebase.auth().signInWithCredential(cred)
.then((result) => {
// User signed in.
})
.catch((error) => {
// Error occurred.
});
Firebase does not support signInWithPopup in a React Native environment.
You can view a full list of supported environments on this page.
You can also submit a feature request for extended Firebase support for React Native here.
If you are using expo bare workflow or simple React native cli (or in simple words which contain android and ios folder) then simply use "React Native Firebase" library.
Here is the link https://rnfirebase.io/
But if you are using expo managed workflow(which donot contain android and ios folder ) then you have to follow below steps .
1.setup google developer account
use this guide to setup : https://docs.expo.dev/versions/latest/sdk/google/
Note that: use host.exp.exponent as the package name.
Another problem you may face in this step is generation of hash,which I also faced,the reason for that error is java dev kit(JDK) is not install ,so do install it before proceeding to this step.
2.Setup Firebase account
Simply setup firebase project as you set before, enable google sign in service
but this time the only change is you have to add client ID of your google developer account in (safest client id field) which will popup once you click on edit Google signin in firebase
look like this
3.Coding Part
import * as Google from 'expo-google-app-auth'; //imported from expo package
import {
GoogleAuthProvider,getAuth
} from 'firebase/auth';
import { initializeApp } from "firebase/app";
import { firebaseconfig } from '[your firebase credentials]';
const app=intitializeApp(firebaseconfig)
const auth=getAuth(app);
async function signInWithGoogleAsync() {
try {
const result = await Google.logInAsync({
androidClientId: 'cliend id from google dev console',
iosClientId: 'client id from google dev console for ios app(if you setup)',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
console.log(result)
const credential = GoogleAuthProvider.credential(result.idToken, result.accessToken);
// Sign in with credential from the Facebook user.
signInWithCredential(auth, credential)
.then(async result => {
console.log(result)
})
.catch(error => { console.log(error) });
return result.accessToken;
} else {
console.log("cancelled by user")
return { cancelled: true };
}
} catch (e) {
console.log(e);
return { error: true };
}//
}