Nuxt + nuxt.auth + MSAL authorization - azure

I'm stuck with office 365 authorization.
Right now i'm using module #nuxtjs/auth-next to get code from azure. Auth goes successful by bringin me code, but then I don't know how to use this code. Do i have to do some redirects or use right configurations. Please help me, guys! My current configurations are:
auth: {
redirect: {
login: '/login',
callback: '/login/submit//',
},
strategies: {
msalAzure: {
scheme: 'oauth2',
endpoints: {
authorization: `https://login.microsoftonline.com/${process.env.VUE_APP_AZURE_AD_TENANT_NAME}/oauth2/v2.0/authorize`,
token: `https://login.microsoftonline.com/${process.env.VUE_APP_AZURE_AD_TENANT_NAME}/oauth2/token`,
userInfo: '',
logout: '/',
},
token: {
property: 'access_token',
type: 'Bearer',
maxAge: 1800,
},
refreshToken: {
property: 'refresh_token',
maxAge: 60 * 60 * 24 * 30,
},
responseType: 'code',
grantType: 'authorization_code',
accessType: 'offline',
clientId: process.env.VUE_APP_AZURE_AD_CLIENT_ID,
codeChallengeMethod: 'S256',
scope: [
'Calendars.ReadWrite',
'MailboxSettings.Read',
'openid',
'profile',
'User.Read',
'email',
],
autoLogout: false,
},
},
},

Related

You don't have permission to access this resource. nuxt npm run generate

In nuxt project, when you refer to an address other than the main address, you will see this message.
(Keep in mind that this does not happen when you are in the app and move to other pages, and only happens when you directly enter the address in the url of the browser!
Can it be from standalone method?)
For example:
cpalizade.ir | is ok
cpalizade.ir/login | not ok(forbidden)
It should be noted that this happens in projects where we use
run generate
and upload dist file in public_html.
but it will not happen when we use
run build
my nuxt.config.js:
import colors from 'vuetify/es5/util/colors'
export default {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
titleTemplate: 'Cp Alizade',
title: 'Cp Alizade',
meta: [{
charset: 'utf-8'
},
{name: "msapplication-TileColor", content: "#da532c"},
{name: "theme-color", content: "#ffffff"},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'
},
{
name: 'apple-mobile-web-app-capable',
content: 'yes'
},
{
name: 'apple-mobile-web-app-status-bar-style',
content: 'default'
},
{
hid: 'description',
name: 'description',
content: ''
},
],
link: [
{rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.jpg"},
{rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon.png"},
{rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon.png"},
{rel: "manifest", href: "/site.webmanifest"},
{rel:"mask-icon", href: "/safari-pinned-tab.svg", color: "#5bbad5"},
],
},
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [
'#/assets/css/main.scss',
'#mdi/font/css/materialdesignicons.min.css'
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
// {
// src: '#/plugins/swiper.js',
// mode: 'client'
// },
// {src: '~/plugins/chart.js', mode: 'client'},
{
src: '#/plugins/vuelidate.js'
},
{
src: '#/plugins/pouchdb.js',
mode: 'client'
},
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
// https://go.nuxtjs.dev/vuetify
['#nuxtjs/vuetify', {
rtl: true,
iconfont: 'mdi'
}],
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
// https://go.nuxtjs.dev/pwa
'#nuxtjs/pwa',
'#nuxtjs/auth-next',
'nuxt-leaflet',
],
auth: {
redirect: {
login: '/login',
logout: '/login',
callback: '/login',
home: '/'
},
strategies: {
local: {
scheme: 'local',
token: {
property: 'access_token',
required: true,
type: 'Bearer'
},
user: {
property: false, // <--- Default "user"
autoFetch: true
},
endpoints: {
login: {
url: 'https://api.cpalizade.ir/api/' + 'users/login',
method: 'post'
},
logout: {
url: 'https://api.cpalizade.ir/api/' + 'users/logout',
method: 'post'
},
user: {
url: 'https://api.cpalizade.ir/api/' + 'user',
method: 'get'
}
}
},
phone: {
scheme: 'local',
token: {
property: 'access_token',
required: true,
type: 'Bearer'
},
user: {
property: false, // <--- Default "user"
autoFetch: true
},
endpoints: {
login: {
url: 'https://api.cpalizade.ir/api/' + 'users/login-w-otp',
method: 'post'
},
logout: {
url: 'https://api.cpalizade.ir/api/' + 'users/logout',
method: 'post'
},
user: {
url: 'https://api.cpalizade.ir/api/' + 'user',
method: 'get'
}
}
}
}
},
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
// See https://github.com/nuxt-community/axios-module#options
baseURL: 'https://api.cpalizade.ir/api/',
credentials: false,
proxy: false,
debug: true,
retry: {
retries: 0
},
requestInterceptor: (config, {
store
}) => {
config.headers.common['Content-Type'] = 'application/x-www-form-urlencoded;application/json';
config.headers.common['Access-Control-Allow-Origin'] = '*';
return config
}
},
// PWA module configuration: https://go.nuxtjs.dev/pwa
pwa: {
manifest: {
name: 'Cp Alizade',
short_name: 'Cp Alizade',
lang: 'fa',
theme_color: '#222',
background_color: '#222',
start_url: `/`,
prefer_related_applications: true,
},
icon: {
fileName: 'favicon.png'
},
},
// Vuetify module configuration: https://go.nuxtjs.dev/config-vuetify
vuetify: {
customVariables: ['~/assets/variables.scss'],
defaultAssets: false,
theme: {
dark: false,
themes: {
light: {
primary: '#1938d3',
secondary: '#ff2626',
info:'#1867c0',
jozi: '#45c235'
},
dark: {
primary: '#1938d3',
accent: colors.grey.darken3,
secondary: colors.amber.darken3,
info: colors.teal.lighten1,
warning: colors.amber.base,
error: '#DF382C',
success: colors.green.accent3
}
}
}
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
extend(config, ctx) {
} // blah blah
}
}
.htaccess file:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
DirectoryIndex 200.html
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /200.html [L]

Can a push notification be send from the server without a client call?

I have a javascript file on my NodeJS server that runs at 00:00:00 and updates some fields in the database, if that happens I want to send out a push notification to some users. I've set this up in my Javascript file:
https://dev.to/devsmranjan/web-push-notification-with-web-push-angular-node-js-36de
const subscription = {
endpoint: '',
expirationTime: null,
keys: {
auth: '',
p256dh: '',
},
};
const payload = {
notification: {
title: 'Title',
body: 'This is my body',
icon: 'assets/icons/icon-384x384.png',
actions: [
{action: 'bar', title: 'Focus last'},
{action: 'baz', title: 'Navigate last'},
],
data: {
onActionClick: {
default: {operation: 'openWindow'},
bar: {
operation: 'focusLastFocusedOrOpen',
url: '/signin',
},
baz: {
operation: 'navigateLastFocusedOrOpen',
url: '/signin',
},
},
},
},
};
const options = {
vapidDetails: {
subject: 'mailto:example_email#example.com',
publicKey: process.env.REACT_APP_PUBLIC_VAPID_KEY,
privateKey: process.env.REACT_APP_PRIVATE_VAPID_KEY,
},
TTL: 60,
};
webpush.sendNotification(subscription, JSON.stringify(payload), options)
.then((_) => {
console.log(subscription);
console.log('SENT!!!');
console.log(_);
})
.catch((_) => {
console.log(subscription);
console.log(_);
});
But when I run the file I get the message:
{ endpoint: '', expirationTime: null, keys: { auth: '', p256dh: '' } } Error: You must pass in a subscription with at least an endpoint.
Which makes sense since the server has no idea about service workers etc. Any suggestions on how to proceed?

How to change access token format using node oidc provider

I implemented node oidc Provider in my project and I got access_token also. but in access token in different format. how to change jwt token format and I added change access_token format to jwt but it could not work. How to resolve it this Issue and I need how to setup adapter config also.
Configuration.ts
const oidc = new Provider('http://localhost:3000', {
adapter:SequelizeAdapter,
clients: [
{
client_id: 'oidcCLIENT',
client_secret: '...',
grant_types: ['refresh_token', 'authorization_code'],
redirect_uris: ['http://sso-client.dev/providers/7/open_id', 'http://sso-client.dev/providers/8/open_id'],
}
],
interactions: {
url(ctx, interaction) { // eslint-disable-line no-unused-vars
return `/interaction/${interaction.uid}`;
},
},
cookies: {
keys: ['some secret key', 'and also the old rotated away some time ago', 'and one more'],
},
claims: {
address: ['address'],
email: ['email', 'email_verified'],
phone: ['phone_number', 'phone_number_verified'],
profile: ['birthdate', 'family_name', 'gender', 'given_name', 'locale', 'middle_name', 'name',
'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'],
},
format:{
AccessToken:'jwt'
},
features: {
devInteractions: { enabled: true }, // defaults to true
mTLS: {
enabled: true,
certificateBoundAccessTokens: true,
selfSignedTlsClientAuth: true,
getCertificate(ctx) {
return unescape(ctx.get('x-ssl-client-cert').replace(/\+/g, ' '));
},
certificateAuthorized(ctx) {
return ctx.get('x-ssl-client-verify') === 'SUCCESS';
},
certificateSubjectMatches(ctx, property, expected) {
if (property !== 'tls_client_auth_subject_dn') {
}
return ctx.get('x-ssl-client-s-dn') === expected;
},
},
claimsParameter: { enabled: true },
deviceFlow: { enabled: true },
dPoP: { enabled: true },
encryption: { enabled: true },
jwtUserinfo: { enabled: true },
introspection: { enabled: true },
registration: { enabled: true },
registrationManagement: { enabled: true, rotateRegistrationAccessToken: true },
jwtResponseModes: { enabled: true },
pushedAuthorizationRequests: { enabled: true },
requestObjects: {
request: true,
requestUri: true,
mode: 'strict',
},
// deviceFlow: { enabled: true }, // defaults to false
revocation: { enabled: true }, // defaults to false
userinfo: {enable:true}
},
findAccount: Account.findAccount,
issueRefreshToken: async (ctx, client, code) => {
return client.grantTypeAllowed('refresh_token') && (code.scopes.has('offline_access') || code.scopes.has('openid') || code.scopes.has('token'));
},
jwks: {
keys: [
{
d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ',
dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0',
dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc',
e: 'AQAB',
kty: 'RSA',
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ',
p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM',
q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M',
qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU',
use: 'sig',
}, {
crv: 'P-256',
d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws',
kty: 'EC',
use: 'sig',
x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4',
y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4',
},
],
},
ttl: {
AccessToken: 24*60*60,//3600,
AuthorizationCode: 24*60*60,//600,
ClientCredentials: 24*60*60,//600,
DeviceCode: 24*60*60,//600,
IdToken: 24*60*60,//3600,
RefreshToken: 24*60*60,//1209600,
},
});
This is happening due to nod oidc provider version. With ver#7, instead of formats:{Access token:'jwt'} ( which worked perfectly in ver#6), you need to provide the resourceIndicators.
Follow this link to know more, Panva(Filip Skoken, author of the library) has given th detailed information.
Discussion on getting JWT token.:
https://github.com/panva/node-oidc-provider/discussions/959
Resource Indicators:
https://github.com/panva/node-oidc-provider/blob/main/docs/README.md#featuresresourceindicators
add the following methods under the features prop from config
resourceIndicators: {
defaultResource: (ctx, client, oneOf) => {
console.log('default resource', client);
return "http://example.com";
},
enabled: true,
getResourceServerInfo: (ctx, resourceIndicator, client) => {
console.log('get resource server info', client);
return ({
audience: 'solid',
accessTokenTTL: 2 * 60 * 60, // 2 hours
accessTokenFormat: 'jwt',
jwt: {
sign: { alg: 'ES256' },
},
});
},
useGrantedResource: (ctx, model) => {
// #param ctx - koa request context
// #param model - depending on the request's grant_type this can be either an AuthorizationCode, BackchannelAuthenticationRequest,
// RefreshToken, or DeviceCode model instance.
return true;
}
},

Implementing facebook login with nodeJS

I am implementing Facebook login in my Vue (nuxt) app with NodeJS backend.
I am able to receive my auth code, but am unable to get the access token using that. It keeps returning me the following error:
data: {
error: {
message: 'Missing redirect_uri parameter.',
type: 'OAuthException',
code: 191,
fbtrace_id: 'AEzwwqCBEvvkq9mDQPrvc-7'
}
}
This is the code I have:
My page containing the facebook login button:
facebookLoginUrl () {
const stringifiedParams = queryString.stringify({
client_id: process.env.facebook_app_id,
redirect_uri: process.env.base_url + this.$findPath('/authenticatie/facebook'),
scope: ['public_profile', 'email', 'user_birthday', 'user_location', 'user_hometown'].join(','), // comma seperated string
response_type: 'code',
auth_type: 'rerequest',
display: 'popup',
})
return `https://www.facebook.com/v4.0/dialog/oauth?${stringifiedParams}`
}
The page where my redirect_uri is going to only contains the following in the created hook:
created () {
let facebookAuthCode = this.$route.query.code
let redirectUri = process.env.base_url + this.$findPath('/authenticatie/facebook')
if (facebookAuthCode) {
this.$getFromBackend('/getFacebookAccessTokenFromCode', { authCode: facebookAuthCode, redirectUri })
}
}
and finally my backend code does this:
axios.get('https://graph.facebook.com/v4.0/oauth/access_token', {
client_id: process.env.facebook_app_id,
client_secret: process.env.facebook_app_secret,
redirect_uri: encodeURIComponent(redirectUri),
code: encodeURIComponent(authCode),
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error.response)
})
And it throws me the error mentioned above.
I can see in the error.response.config object the following:
config: {
url: 'https://graph.facebook.com/v4.0/oauth/access_token',
method: 'get',
headers: {
Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/0.19.2'
},
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
client_id: 'xxxxxxxxxxxxxx',
client_secret: 'xxxxxxxxxxxxxxxxxx',
redirect_uri: 'http://localhost:3000/nl-be/authenticatie/facebook',
code: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
data: undefined
},
So the redirect_uri is set, whats going on?
UPDATE: I changed the axios code according to #CBroe answer:
axios.get('https://graph.facebook.com/v4.0/oauth/access_token', qs.stringify({
client_id: process.env.facebook_app_id,
client_secret: process.env.facebook_app_secret,
redirect_uri: encodeURIComponent(redirectUri),
code: encodeURIComponent(authCode),
}), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error.response)
})
But i am getting the exact same error.

passport-linkedin-oauth2 not returning email address

Here is my console.log(profile);
{ provider: 'linkedin',
id: 'LJitOAshpU',
displayName: 'Monist BD',
name: { familyName: 'BD', givenName: 'Monist' },
emails: [ { value: undefined } ],
_raw: '{\n "firstName": "Monist",\n "formattedName": "Monist BD",\n "id": "
LJitOAshpU",\n "lastName": "BD"\n}',
_json:
{ firstName: 'Monist',
formattedName: 'Monist BD',
id: 'LJitOAshpU',
lastName: 'BD' } }
here is my routing code:
app.get('/auth/linkedin',passport.authenticate('linkedin', { scope: ['r_emailaddress', 'r_basicprofile', 'rw_nus'],state: 'DCEEFWF45453sdffef424' }));
app.get('/auth/linkedin/callback',passport.authenticate('linkedin', { failureRedirect: '/' }),users.authCallback);
here is passport.js config:
passport.use(new LinkedInStrategy({
clientID: config.linkedIn.clientID,
clientSecret: config.linkedIn.clientSecret,
callbackURL: config.linkedIn.callbackURL,
profileFields: ['id', 'first-name', 'last-name', 'email-address','public-profile-url'],
passReqToCallback: true
},
function(req,token, refreshToken, profile, done) {
console.log(profile);
}));
Why am I getting undefined in email values? It worked when I used passport-linkedin
According to the readme, the scope option must be set in the Strategy object. You are setting it in passport.authenticate where it is being ignored.
To fix this change your code to:
app.get('/auth/linkedin',passport.authenticate('linkedin', { state: 'DCEEFWF45453sdffef424' }));
app.get('/auth/linkedin/callback',passport.authenticate('linkedin', { failureRedirect: '/' }),users.authCallback);
...
passport.use(new LinkedInStrategy({
clientID: config.linkedIn.clientID,
clientSecret: config.linkedIn.clientSecret,
callbackURL: config.linkedIn.callbackURL,
scope: ['r_emailaddress', 'r_basicprofile', 'rw_nus'],
profileFields: ['id', 'first-name', 'last-name', 'email-address','public-profile-url'],
passReqToCallback: true
},
function(req,token, refreshToken, profile, done) {
console.log(profile);
}));
you need to give permission in your LinkedIn APP like below.
IN this image you can see i have given many permission like in this emailaddress also check so i will get that

Resources