Using Microsoft Authentication Library MSAL with PnPjs - reactjs

I've been reading the PnPjs page and I need to understand what it does:
https://pnp.github.io/pnpjs/authentication/msaljsclient/#calling-sharepoint-via-msal
It seems like:
import { MsalClientSetup } from "#pnp/msaljsclient";
import { sp } from "#pnp/sp/presets/all";
sp.setup({
sp: {
fetchClientFactory: MsalClientSetup({
auth: {
authority: "https://login.microsoftonline.com/mytentant.onmicrosoft.com/",
clientId: "00000000-0000-0000-0000-000000000000",
redirectUri: "https://mytentant.sharepoint.com/sites/dev/SitePages/test.aspx",
},
}, ["https://mytentant.sharepoint.com/.default"]),
},
});
const r = await sp.web();
Is providing a wrapper for a SharePoint app to be given perhaps an impersonation step, or for the app creator to allow other users to have elevated permissions? If not (oh I wish) then what does it do?

you have to add baseUrl in the setup.
import { MsalClientSetup } from "#pnp/msaljsclient";
import { sp } from "#pnp/sp/presets/all";
sp.setup({
sp: {
baseUrl: "https://{my tenant}.sharepoint.com/sites/dev/",
fetchClientFactory: MsalClientSetup({
auth: {
authority: "https://login.microsoftonline.com/mytentant.onmicrosoft.com/",
clientId: "00000000-0000-0000-0000-000000000000",
redirectUri: "https://mytentant.sharepoint.com/sites/dev/SitePages/test.aspx",
},
}, ["https://mytentant.sharepoint.com/.default"]),
},
});
const r = await sp.web();
After adding baseUrl we can get SharePoint data and it's working with above code.

Related

Cannot get the additional detail i.e account id from session callback using Next_auth

I want to extract account id as additional detail from session callback using Next_auth. Whatevere I add in jwt token and pass it to session callback still it returns the same data. I tried logging out and loggin in many times but all in vain. Any help will be appreciated.
Code in pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google";
import FacebookProvider from "next-auth/providers/facebook";
export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code"
}
}
}),
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET
})
],
secret: process.env.SECRET,
session:{
strategy:"jwt"
},
callback: {
async jwt({ token, account, user }) {
// Persist the OAuth access_token to the token right after signin
if (user) {
token.id = account.id;
}
return token
},
async session({ session, token }) {
// Send properties to the client, like an access_token from a provider.
session.user.id = token.id;
return session;
},
// redirect: async(url, _baseUrl) => {
// if (url === "/profile") {
// return Promise.resolve("/");
// }
// return Promise.resolve("/");
// }
}
})
Code in login page
import { useSession, getSession, signIn } from "next-auth/react"
useEffect(() => {
const good = async () => {
const session = await getSession();
if (session) {
console.log(session);
}
}
good();
}, [])
Result I get is
{"user":{"name":"myname","email":"myemail","image":"imageUrl"},"expires":"2022-09-05T11:28:41.840Z"}

Need to differentiate login callback credentials from google and facebook using next-auth

I am getting data successfully from google and facebook login using next-auth. I want to save separate profiles for Google and Facebook as well. Data I am getting is name, image, email and session expiry but I need to differentiate the callback data. Maybe a provider name would work. I have tried to add provider in session and use it in page but in vain
Here is code for pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google";
import FacebookProvider from "next-auth/providers/facebook";
export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code"
}
}
}),
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET
})
],
jwt: {
encryption: true
},
secret: process.env.SECRET,
callback: {
async jwt({ token, account }) {
// Persist the OAuth access_token to the token right after signin
if (account) {
token.accessToken = account.access_token;
}
if (account?.provider) {
token.provider = account.provider;
}
return Promise.resolve(token);
},
async session({ session, token }) {
// Send properties to the client, like an access_token from a provider.
session.accessToken = token.accessToken;
session.provider = token.provider;
return Promise.resolve(session);
},
// redirect: async(url, _baseUrl) => {
// if (url === "/profile") {
// return Promise.resolve("/");
// }
// return Promise.resolve("/");
// }
}
})
Here is code for login page
const {data:session} = useSession();
{JSON.stringify(session, 4)};
Result I get is
{"user":{"name":"myname","email":"myemail","image":"myimage"},"expires":"2022-09-04T16:40:10.809Z"};

#azure/msal-browser untrusted_authority error

I've been trying to follow this tutorial...
Sign In Users From A React SPA
but I cannot get it to work. I have a personal azure account and have created an SPA application within Azure Active Directory to get a client id.
From everything I've read it says I should use https://login.microsoftonline.com/{tenant-id-here} as my authority but when I do I get the error...
ClientConfigurationError: untrusted_authority: The provided authority is not a trusted authority
I have tried adding a knownAuthorities parameter to the config, although I don't think I should have to as I'm just concerned with a single tenant.
When I do add the knownAuthorities param, the error changes to...
ClientAuthError: openid_config_error: Could not retrieve endpoints.
My config file looks like this
export const msalConfig = {
auth: {
clientId: '{client id from Azure AD Application}',
authority: 'https://login.microsoftonline.com/{tenant-id}',
redirectUri: 'http://localhost:3000',
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false
}
}
The sign in button that causes the error looks like this...
function handleLogin(instance) {
instance.loginPopup(loginRequest).catch(e => {
console.error(e);
})
}
function SignInButton() {
const {instance} = useMsal();
return (
<Button variant="secondary" className="ml-auto" onClick={() => handleLogin(instance)}>
Sign in
</Button>
)
}
Might I be missing something in the azure settings? Or something else in the react application itself?
UPDATE: 16/02/22
Well I've now got it working. I accidentally had the sign in button rendered inside an <a> tag, which must have been stopping the Microsoft login popup from loading. Probably trying to redirect somewhere, which prevented the MSAL process from finishing. Wasn't the most helpful error message to go on.
So to confirm, for a single tenant solution, you only need clientId and authority. And authority is definitely https://login.microsoftonline.com/{your-tenant-id}
I took a look on Github and the settings are a bit different. Try using "https://login.microsoftonline.com/common" as the authority:
const msalConfig = {
auth: {
clientId: "enter_client_id_here",
authority: "https://login.microsoftonline.com/common",
knownAuthorities: [],
cloudDiscoveryMetadata: "",
redirectUri: "enter_redirect_uri_here",
postLogoutRedirectUri: "enter_postlogout_uri_here",
navigateToLoginRequestUrl: true,
clientCapabilities: ["CP1"]
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
secureCookies: false
},
system: {
loggerOptions: {
loggerCallback: (level: LogLevel, message: string, containsPii: boolean): void => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
}
},
piiLoggingEnabled: false
},
windowHashTimeout: 60000,
iframeHashTimeout: 6000,
loadFrameTimeout: 0,
asyncPopups: false
};
}
const msalInstance = new PublicClientApplication(msalConfig);
source: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md
Kindly add the knownAuthorities, and it's worked for my sample
const msalConfig = {
auth: {
clientId: 'enter_client_id_here',
// comment out if you use a multi-tenant AAD app
authority: 'https://login.microsoftonline.com/{tenant-id}',
knownAuthorities: ["login.microsoftonline.com"],
redirectUri: 'http://localhost:8080'
}
};

Store and authenticate FB/Google users from NextAuth to another backend api in Nextjs

I'm using Next.js(v.10.0.4) and NextAuth(v.3.23.3) for a project which requires social authentication. I'm able to login/logout via a custom login page including a session-based social authentication system provided by NextAuth.
Now I would like to store the user's information in an external API and later on, I'd like to fetch the user's data via JWT.
I'm not sure how should I approach this. Any suggestion/example/solution idea will be highly appreciated. Thanks :)
api/[...nextauth].js]
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import axios from 'axiosConfig'
const options = {
providers: [
Providers.Facebook({
clientId: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
}),
Providers.Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
pages: {
signIn: '/',
signOut: '/',
error: '/auth/error', // Error code passed in query string as ?error=
verifyRequest: '/auth/verify-request', // (used for check email message)
newUser: null, // If set, new users will be directed here on first sign in
},
session: {
jwt: true,
},
callbacks: {
session: async (session, user) => {
session.jwt = user.jwt
session.id = user.id
return Promise.resolve(session)
},
jwt: async (token, user, account) => {
const isSignIn = user ? true : false
if (isSignIn) {
//
}
return Promise.resolve(token)
},
},
}
export default (req, res) => NextAuth(req, res, options)

Msal 2.0 - how to generate Sign Up link with Azure B2C?

In my angular app I use Azure AD B2C for authentication and MSAL.js 2.0 library to handle it. I have a "Log In" button on the home page, that is easy. But I also need a "Sign Up" button, so user would be redirected straight to Azure B2C 'Sign Up' page. Is this possible?
It is possible to redirect straight to Azure AD B2C signup page by creating individual sign-in and sign up policies and make the below changes. It won't be possible with single sign-in signup policy.
In the app config.ts add the below changes
export const b2cPolicies = {
names: {
SignIn: "b2c_1_SignIn",
signup: "B2C_1_signup",
resetPassword: "b2c_1_reset",
},
authorities: {
SignIn: {
authority: "https://fabrikamb2c.com/fabrikamb2c.onmicrosoft.com/B2C_1_SignIn"
},
signup: {
authority: "https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/B2C_1_signuptest"
},
resetPassword: {
authority: "https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_reset"
}
}
}
Create a signup button and add signup click function
signup() {
this.authService.loginPopup(b2cPolicies.authorities.signup)
}
We can use single sign-in signup policy and single signin or signup policy.
This method is for display signup signin policy:
export const msalConfig = {
auth: {
clientId: "your app client id",
authority:
"https://XXX.b2clogin.com/XXX.onmicrosoft.com/<b2c policy name>",
redirectUri: AZURE_REDIRECT_URI,
postLogoutRedirectUri: "/",
knownAuthorities: [
"https://XXX.b2clogin.com/XXX.onmicrosoft.com/<b2c policy name>",
redirectUri: AZURE_REDIRECT_URI",
],
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true,
},
};
export const loginRequest = {
scopes: ["https://XXX.onmicrosoft.com/api/XXX"],
};
//Click on login
const handleLogin = () => {
instance.loginPopup(loginRequest);
};
This method is for display individual signup policy:
const handleSignup = () => {
instance.loginPopup({
authority:
"https://XXX.b2clogin.com/tfp/XXX.onmicrosoft.com/<b2c policy name>",
clientId: "your app client id",
redirectUri: AZURE_REDIRECT_URI,
postLogoutRedirectUri: "/",
knownAuthorities: [
"XXX.b2clogin.com/rentpundit1.onmicrosoft.com/<b2c policy name>",
],
protocolMode: "OIDC",
});

Resources