Cannot read outlook profile using passport-outlook strategy with nestjs - passport.js

Always getting the following error while using passport-outlook strategy with scopes scope: ['openid', 'profile', 'offline_access']
In the nest middleware,
consumer.apply(authenticate('outlook', {
session: false,
accessType: 'offline',
scope: ['openid', 'profile', 'offline_access'],
callbackURL: `${callbackUrl}/auth/outlook/login/callback`,
})).forRoutes(
{ path: '/auth/outlook/login', method: RequestMethod.GET },
{ path: '/auth/outlook/login/callback', method: RequestMethod.GET },
)
}
{"error":{"code":"InvalidMsaTicket","message":"ErrorCode:
'PP_E_RPS_CERT_NOT_FOUND'. Message: ' Internal error:
spRPSTicket->ProcessToken failed. Failed to call
CRPSDataCryptImpl::UnpackData: Internal error: Failed to decrypt data.
:Failed to get session key. RecipientId=293577. spCache->GetCacheItem
returns error.:Cert Name: (null). SKI:
45237f1479435b9c4def8b7a1b36edb0105e0546...'","innerError":{"requestId":"4ea03cf1-79f8-421f-a0eb-d5bc6560da6a","date":"2019-07-05T08:44:20"}}}
Did I missed anything in the azure app registration config ?

Do you set up passport.use(new OutlookStrategy({})) in main function with providing there clientID and clientSecret?

Related

How to configure extraQueryParameters for redirect request in MSAL.js

My react app uses MSAL (#azure/msal-browser) for user authentication, so I configure MSAL instance in my index.tsx using configuration object:
const config = {
clientId: "myAppId",
msalConfig: {
auth: {
authority: "signUpSignInCustomPolicyURI",
clientId: "myAppId",
knownAuthorities: ["myB2CTenant.b2clogin.com"],
redirectUri: "/"
},
cache: {<cacheconfig>}
},
loginScopes: ['openid', 'offline_access'],
authorities: {
signUpSignIn: "signUpSignInCustomPolicyURI",
forgotPassword: "forgotPasswordCustomPolicyURI",
}
}
msalInstance = new PublicClientApplication(config);
Then I wrap my app component in MsalProvider component:
<MsalProvider instance={msalInstance}>
<App/>
</MsalProvider>
and use <MsalAuthenticationTemplate> in protected components so users are prompted to login automatically.
On the other hand, we have an ability to add extra parameters to RequestRedirect like this:
const { instance } = useMsal();
const loginRedirectRequest = {
scopes: <myLoginScopes>,
extraQueryParameters: {
locale: "localeId",
theme: "themeId"
}
};
instance.loginRedirect(loginRedirectRequest);
My question is how to configure MSAL instance so it would apply extraQueryParameters every time it redirects users automatically?
Add it into the MSAL config object to start with.
const config = {
clientId: "myAppId",
msalConfig: {
auth: {
authority: "signUpSignInCustomPolicyURI",
clientId: "myAppId",
knownAuthorities: ["myB2CTenant.b2clogin.com"],
redirectUri: "/"
},
cache: {<cacheconfig>}
},
loginScopes: ['openid', 'offline_access'],
authorities: {
signUpSignIn: "signUpSignInCustomPolicyURI",
forgotPassword: "forgotPasswordCustomPolicyURI",
},
extraQueryParameters: {
locale: "localeId",
theme: "themeId"
}
}
msalInstance = new PublicClientApplication(config);

TS - NodeMailer OAuth2 'auth' does not exist in type 'TransportOptions

I have a problem. I need to make email sending function with Gmail api. In docs it tells me to make a createTransport function like this:
const transport = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: "horvatlucian1#gmail.com",
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
refreshToken: REFRESH_TOKEN,
accessToken: accessToken,
},
})
DOCS
But it all turns red and returns:
Error
Any solution? Thanks.
There is a problem of type script when you tring to pass the accessToken because in google oauth2client the return type of getAccessToken() is https://github.com/googleapis/google-auth-library-nodejs/blob/b0ddb7512fb9ed1e51b6874b7376d7e1f26be644/src/auth/oauth2client.ts#L331
that not supported by the types of nodemailer that should be string:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/7827d853a1d623dd5345d9a11ced3e15eb5d3d8b/types/nodemailer/lib/xoauth2.d.ts#L24
by looking at the return type of the getAccessToken you can see that the token is inside that have type string so to fix that just destructure your token from the accessToken.
const transport = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: "horvatlucian1#gmail.com",
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
refreshToken: REFRESH_TOKEN,
accessToken: accessToken.token,
},
})
1/
const transport = nodemailer.createTransport({
service: String("gmail") || "",
auth: {
type: String("OAuth2"),
user: String(SENDER_MAIL),
clientId: String(CLIENT_ID),
clientSecret: String(CLIENT_SECRET),
refreshToken: String(REFRESH_TOKEN),
access_token: String(access_token),
},
});
and the ERRO WITH MSG :
[ERROR] 14:02:23 ⨯ Unable to compile TypeScript:
server/config/sendmail.ts(25,7): error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type '{ service: string; auth: { type: string; user: string; clientId:string; clientSecret:string; refreshToken:string; access_token:GetAccessTokenResponse; }; }' is not assignable to parameter of type 'TransportOptions | Transport<unknown>'.
Object literal may only specify known properties, and 'service' does not exist in type 'TransportOptions | Transport<unknown>'.
The accessToken required in nodemailer.createTransport is nullable
Because of that, to avoid error, you must cover the case when accessToken is null by providing an empty string or something similar to avoid null error
const transport = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: process.env.EMAIL_ADDRESS,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: accessToken.token || '',
},
})
Hopefully that help

Could not load email provider "nodemailer" (Strapi)

I'm trying to setup the strapi application with nodemailer.
I've added the nodemailer dependency with yarn add #strapi/provider-email-nodemailer as on the official page described. Afterwards I've added the following configuration to my plugins.js file (I've replaced sensitive informations with XXXXXXXX):
module.exports = ({ env }) => ({
email: {
config: {
provider: 'nodemailer',
providerOptions: {
host: env('SMTP_HOST', 'XXXXXXXX'),
port: env('SMTP_PORT', 587),
auth: {
user: env('SMTP_USERNAME', 'XXXXXXXX'),
pass: env('SMTP_PASSWORD', 'XXXXXXXX'),
},
secure: true
},
settings: {
defaultFrom: 'XXXXXXXX',
defaultReplyTo: 'XXXXXXXX',
},
},
},
});
But when I try to strap Strapi with yarn develop I get the following error message:
C:\Dev\Strapi\Projects\strapi>yarn develop
yarn run v1.22.15
$ strapi develop
Building your admin UI with development configuration ...
Admin UI built successfully
[2021-12-27 23:27:51.485] debug: ⛔️ Server wasn't able to start properly.
[2021-12-27 23:27:51.487] error: Could not load email provider "nodemailer".
Error: Could not load email provider "nodemailer".
at createProvider (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\plugin-email\server\bootstrap.js:23:11)
at Object.module.exports [as bootstrap] (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\plugin-email\server\bootstrap.js:31:37)
at Object.bootstrap (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\core\domain\module\index.js:40:47)
at Object.bootstrap (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\core\registries\modules.js:28:19)
at async Strapi.runLifecyclesFunctions (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\Strapi.js:463:5)
at async Strapi.bootstrap (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\Strapi.js:401:5)
at async Strapi.load (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\Strapi.js:410:5)
at async Strapi.start (C:\Dev\Strapi\Projects\strapi\node_modules\#strapi\strapi\lib\Strapi.js:161:9)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
What am I doing wrong? The configuration seems so simple so I don't have any idea what's wrong.
You need remove config section:
email: {
provider: 'nodemailer',
providerOptions: {
host: env('SMTP_HOST', 'smtp.xxxxxx.xx'),
port: env('SMTP_PORT', xxx),
secure: true,
auth: {
user: env('SMTP_USERNAME'),
pass: env('SMTP_PASSWORD'),
},
},
settings: {
defaultFrom: env('SMTP_FROM_EMAIL'),
defaultReplyTo: env('SMTP_REPLY_EMAIL'),
},
},
UPD: Sorry, I understood now that I use this package https://www.npmjs.com/package/strapi-provider-email-nodemailer and you used this https://www.npmjs.com/package/#strapi/provider-email-nodemailer

How to implement Joi validation in hapi.js?

I just want to implement Joi in Hapi API.
server.route([
{
method: 'POST',
path: '/login',
config: {
tags: ['login', 'auth'],
auth: false,
validate: {
payload: payloadValidator,
failAction: (req, h, source, error) => {
console.log("Error ::: ", source.details[0].message);
return h.response({ code: 0, message: source.details[0].message });
}
}
},
handler: async (request, h) => {
console.log(request.payload.email);
console.log(request.payload.password);
...
}
}
]);
Hear I call payloadValidator.
const payloadValidator = Joi.object({
email: Joi.string().required(),
password: Joi.string().required()
}).options({ allowUnknown: true });
Actually I'm new with hapi and I'm missing something in my code. Can anyone help me to fix this issue?
Required output
If I do not pass email then the app must throw an error of Email is required and it should be the same with the password field also.
Error:
Error ::: "email" is required
Debug: internal, implementation, error
Error: Lifecycle methods called before the handler can only return an error, a takeover response, or a continue signal
at Request._lifecycle (/var/www/html/hapi/node_modules/#hapi/hapi/lib/request.js:326:33)
at process._tickCallback (internal/process/next_tick.js:68:7)
As an error suggests Lifecycle methods called before the handler can only return an error, a takeover response, or a continue signal you have to return takeover response.
return h.response({ code: 0, message: source.details[0].message }).takeover();
For more information you can visit this link : reference link

ValidationError: "tenantId" is not allowed when using AzureAD for hapi JS route authorization

We are trying to use #hapi/bell on our back-end routes to provide authorization. The authentication strategy uses azure as provider and the scheme is bell
This is how I register the strategy. The clientId, clientSecret, tenantId and password are hidden for obvious reasons
server.auth.strategy('azureAD', 'bell', {
provider: 'azure',
clientId: '...',
clientSecret: '...',
tenantId: '...',
password: '...',
providerParams: {
response_type: 'code'
},
scope: ['openid', 'offline_access', 'profile', 'User.Read']
})
When I run the server, I get the following error:
{ [ValidationError: "tenantId" is not allowed] ...
Now, looking into the azure portal, we definitely want to be supporting accounts only inside the organisation i.e. single-tenant.
If I remove the tenantId option and restart the server I get CORS error which essentially says that our app is not configured as a multi-tenant application and we need to use a tenant-specific endpoint or configure the application to be multi-tenant. Adding the tenantId, however, says that it is not allowed.
Any guidance as to why this is happening will be highly appreciated.
I found out that instead of registering the strategy as I have shown in the question the following could be done:
const custom = Bell.providers.azure({ tenant: '...' })
server.auth.strategy('azureAD', 'bell', {
provider: custom,
clientId: '...',
clientSecret: '...',
password: '...',
isSecure: false, // look into this, not a good idea but required if not using HTTPS
providerParams: {
response_type: 'code'
},
scope: ['openid', 'offline_access', 'profile', 'User.Read']
})
This gets rid of the "tenantId" is not allowed error, however, we now get a different error stating Authentication failed due to: Missing custom request token cookie.
Bell suggests that a common solution is to combine bell with the hapi-auth-cookie authentication scheme plugin, so now this is something to look into.
The Joi package is validating the schema and throwing errors. See config property below. It overrides options and avoids the "tenantId" or "tenant" is not allowed error you are seeing. Also, in recent versions Bell Azure Provider wants "tenant" not "tenantId" property.
server.auth.strategy('azureAD', 'bell', {
provider: 'azure',
config: {
tenant: '...',
useParamsAuth: false,
},
clientId: '...',
clientSecret: '...',
password: '...',
providerParams: {
response_type: 'code'
},
scope: ['openid', 'offline_access', 'profile', 'User.Read'],
isSecure: false,
})

Resources