Get an access token to Linkedin API using email and password - node.js

Is it possible to get an access token in order to use node-linkedin package by providing credentials - user email and password? What I'm trying to do is an command line app, that can make an api calls to linkedin and write results in a text file. Thus, I'm not sending any api call results to the client.

I've been trying to do the same thing.
the simple-oauth2 module has a method for logging in via password, but I cannot seem to get it to work.
https://www.npmjs.com/package/simple-oauth2
// Set the configuration settings
const credentials = {
client: {
id: '<client-id>',
secret: '<client-secret>'
},
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
};
// Initialize the OAuth2 Library
const oauth2 = require('simple-oauth2').create(credentials);
// Get the access token object.
const tokenConfig = {
username: 'username',
password: 'password'
};
// Callbacks
// Save the access token
oauth2.ownerPassword.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const token = oauth2.accessToken.create(result);
});
I am not sure these endpoints are correct:
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
I get a 400 bad request.

Related

Auth0 & Next-Auth Malformed JWT

I am attempting to setup authentication in my NextJS project and I am using Next-Auth. I am currently trying to setup a simple GET /me route that would be hit through React Query using the access_token retrieved by a successful Auth0 session Login.
BUT: the access_token received form Next-Auth w/ Auth0 useSession() is malformed
EDIT: I think the issue is that next-auth / auth0 is storing the token as an encrypted JWE. I need to figure out how to decrypt this and pass it to my api
https://github.com/nextauthjs/next-auth/issues/243
https://github.com/nextauthjs/next-auth/pull/249
https://github.com/nextauthjs/next-auth/discussions/5214
FRONTEND
in my pages > api > auth > [...nextauth].js I have the following configuration
const authOptions = {
providers: [
Auth0Provider({
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
issuer: process.env.AUTH0_ISSUER,
idToken: true,
}),
],
// Configure callbacks 👉 https://next-auth.js.org/configuration/callbacks
callbacks: {
// The JWT callback is called any time a token is written to
jwt: ({ token, user, account, profile, isNewUser }) => {
if (account) {
token.access_token = account.access_token;
token.id_token = account.id_token;
token.auth0_id = token.sub;
token.type = account.token_type;
}
delete token.name;
delete token.picture;
delete token.sub;
return token;
},
// The session callback is called before a session object is returned to the client
session: ({ session, user, token }) => {
const newSession = {
user: {
auth0_id: token.auth0_id,
email: token.email,
},
token: {
access_token: token.access_token,
id_token: token.id_token,
token_type: token.type,
},
};
return newSession;
},
},
secret: process.env.NEXTAUTH_SECRET,
};
export default NextAuth(authOptions);
Auth0 Config
in Auth0 Dashboard: Auth0 > Applications > Applications > <PROJECT_NAME> > AdvancedSettings > OAuth the signature algorithm is RS256
Successful Login Landing Page
here I am using const { data: session, status } = useSession(); to extract the value of the current session (which matches the shape created in the session callback of pages > api > auth > [...nextauth].js -- and has the access_token)
_app.jsx component
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</SessionProvider>
);
}
API Requests (from the frontend)
for each API request to the server I am setting the headers as such
if (token) headers["authorization"] = `Bearer ${token}`;
headers["Content-Type"] = "application/json";
Server Middleware
I created an auth middleware function that serves 2 purposes.
Validate the JWT passed to the route (🚨 THIS IS WHERE THINGS BREAK 🚨)
Attempt to find a user in my postgres DB with matching auth0_id (auth0|)
below is the auth middleware
// Auth0
import { isPublicRoute } from "../services/auth0/index.js";
import { expressjwt } from "express-jwt";
import jwks from "jwks-rsa";
// 👀 I have copied this directly from the Auth0 Dashboard: Applications > APIs > QuickStart
// 🚨 the express-jwt library is failing - error below
const validator = expressjwt({
secret: jwks.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: "https://dev-ikfyop4g.us.auth0.com/.well-known/jwks.json",
}),
audience: "thunderbolt",
issuer: "https://dev-ikfyop4g.us.auth0.com/",
algorithms: ["RS256"],
});
// NOTE: 👀 we are not actually getting to this function
// This function will retrieve the user and feed it into the request
// into a populated user model, if the id is not in the database it
// will create a new user and pull the base data from auth0
const userInjector = async (req, res, next) => {
if (isPublicRoute(req)) return next();
if (!req.auth0?.sub) throw badImplementation("JWT missing in userInjector");
req.user = await userFromReq(req);
console.log("THE USER INJECTOR RESULT :: req.user", req.user);
next();
};
const auth = () => {
return [validator, userInjector];
};
export default auth;
Inside my server I am importing this auth middleware function and using like this
server.use(auth());
THE express-jwt ERROR
UnauthorizedError: jwt malformed
at new UnauthorizedError (/Users/mrt/Documents/MrT/code/M/bolt/node_modules/express-jwt/dist/errors/UnauthorizedError.js:22:28)
at /Users/mrt/Documents/MrT/code/M/bolt/node_modules/express-jwt/dist/index.js:133:35
at step (/Users/mrt/Documents/MrT/code/M/bolt/node_modules/express-jwt/dist/index.js:33:23)
at Object.next (/Users/mrt/Documents/MrT/code/M/bolt/node_modules/express-jwt/dist/index.js:14:53)
at fulfilled (/Users/mrt/Documents/MrT/code/M/bolt/node_modules/express-jwt/dist/index.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
The access_token that I am receiving from Auth0 is malformed. Upon further investigation I would agree. The AccessToken I am receiving (as a JWT) has 5 parts (parts are strings separated by a period ..
Access Token From Auth0 Session
eyJhbGc<REMOVED_CHUNK>uYXV0aDAuY29tLyJ9.. // 2 period w/ nothing inbetween??
zOKQ2<REMOVED_CHUNK>rSm6.
9qbS5yndGKkrZ9Tc_dL8ZOuHtp_-e58uGqvGHgcpcFS8-s6SEHJYZ0_g7Ii7aYQe4AdbeK9ekW-704X_6C1r5JH3-9yBz<REMOVED_CHUNK>6Rn3Q8U0YC_x8Vp9pF_EA4GHjevXrh3HFBzCY4AEAx-Rmnzk4tZDgk3oU2rsY1NleMTwpIj0h29KIsukg113uMt5KCWKVnosSI-psaBu<REMOVED_CHUNK>lf0R_y5ClcXF6XY0ezIvuwoSQOmhulMlPsTxzBVGeoIhsooNntgAc4s.
ojmkoO_CO<REMOVED_CHUNK>URg
If everything is configured for RS256 why is Next-Auth w/ Auth0 sending me a malformed JWT.
EDIT: a 5 part JWT is a JSON Web Encryption (JWE) token...?

Google OAuth2.0 - Gaxios invalid_grant error

The below is my mailer.js code
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const { OAuth2 } = google.auth;
const oauth_link = "https://developers.google.com/oauthplayground";
const { EMAIL, MAILING_ID, MAILING_REFRESH, MAILING_SECRET } = process.env;
const auth = new OAuth2(
MAILING_ID,
MAILING_SECRET,
MAILING_REFRESH,
oauth_link
);
exports.sendVerificationEmail = (email, name, url) => {
console.log("inside send verification email");
auth.setCredentials({
refresh_token: MAILING_REFRESH,
});
const accessToken = auth.getAccessToken();
console.log("accessToken-" + accessToken);
const smtp = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: EMAIL,
clientId: MAILING_ID,
clientSecret: MAILING_SECRET,
refreshToken: MAILING_REFRESH,
accessToken,
},
});
console.log("smtp " + smtp);
const mailOptions = {
from: EMAIL,
to: email,
subject: "Facebook email verification",
html: '<div><div style="max-width:500px;margin-bottom:1rem;align-items:center;display:flex"><img style="width:40px" src="https://seeklogo.com/images/F/facebook-icon-circle-logo-09F32F61FF-seeklogo.com.png" alt=""><span style="font-family:sans-serif;color:#3266a8;font-weight:700;padding-left:10px">Action Required : Activate your facebook account</span></div><div style="border-top:1px solid;border-bottom:1px solid;border-color:#deb887;padding:10px;padding-bottom:20px"><div style="height:35px"><span style="font-weight:700;font-family:sans-serif">Hello ${name}</span></div><div style="height:28px;font-family:sans-serif;padding-bottom:20px"><span>You recently created a profile on facebook. Please confirm your account</span></div><div style="">Confirm Your Account</div></div></div>',
};
console.log("mailOptions" + mailOptions);
smtp.sendMail(mailOptions, (err, res) => {
if (err) return err;
return res;
});
};
I have properly generated the Oauth playground configurations and have the below in my process.env
EMAIL=***
MAILING_ID=***
MAILING_SECRET=***
MAILING_REFRESH=***
MAILING_ACCESS=***
I am getting the below error.
GaxiosError: invalid_grant
***
***
data: {
error: 'invalid_grant',
error_description: 'Token has been expired or revoked.'
},
I am totally beginner with the Google OAuth procedure. Which token has expired? Is it Access token or Refresh Token.
Thanks in advance, Dear Developers community..
The refresh token you are using has expired. You need to request a new one. If your project is still in testing refresh tokens only last for seven days.
You need to set it to production in Google cloud console under the OAuth screen and your refresh tokens will no longer expire
I applaud your use of xOAuth2 with the smtp server 👏

Angular/NodeJS share frontend access token to fetch data from MS graph by backend

I have a small MEAN stack running (Angular in Frontend and NodeJS in Backend). The Frontend is protected by MSAL (#azure/msal-angular).
This part is working fine. The user gets authorized for the frontend and Angular is able to request data from MS Graph (the msal interceptor adds the token to all requests to the MS Graph and the backend):
app.module.ts
MSalModule.forRoot( new PublicClientApplication({ // MSAL Configuration
auth: {
clientId: environment.aad_client_id,
authority: 'https://login.microsoftonline.com/' + environment.aad_tenant_id + '/',
redirectUri: window.location.origin,
},
cache: {
cacheLocation : BrowserCacheLocation.LocalStorage,
storeAuthStateInCookie: isIE,
}
}), {
// MSAL Guard Configuration
interactionType: InteractionType.Redirect,
authRequest: {
scopes: ['user.read', environment.aad_scope_api]
}
}, {
// MSAL Interceptor Configuration
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['https://graph.microsoft.com/v1.0', ['user.read']],
[environment.apiUrl, [environment.aad_scope_api]],
])
})
After redirect from MS login I send a post request to my NodeJS Backend to establish a session.
The login route of the Backend should extract the token from the header, and send some request to the graph, to store the user details from there in the user session.
login.js
router.post('/login', (req, res) => {
if (req.session.user) {
res.json(req.session.user);
} else {
fetchUser(req, mongodb).then(result => {
req.session.user = result;
res.json(result);
}).catch(err => {
res.status(401).json(err);
})
}
});
...
async function fetchUser(token) {
try {
const token = req.headers.authorization;
request({
headers: { 'Authorization': token },
uri: 'https://graph.microsoft.com/v1.0/me',
method: 'GET'
}, { json: true }, (err, res, body) => {
if (err) { throw err; }
const obj = ...do some things
return obj;
});
} catch(err) {
throw err;
}
}
The issue is, that the token is only valid from Frontend. MS recommend the on-behalf-of-flow for that, but I'm not able to find any way to solve this. So how can I request a new token for my backend?
You can request a token for the backend to access Graph using the client credentials authentication, and set the scopes for Graph as Application Permissions on the App Registration, such as User.Read.All.
You would instead read the "oid" from the AAD access token passed from frontend to backend for discovering the user for formatting requests to Graph. Microsoft created a tutorial on implementing which you may find helpful.

Not able to watch Admin Users Directory using `google-admin-sdk`

I am trying to connect to the G-Suite's User directory using the google-admin-sdk. I am using an API Key for authorization and I am not able to reach a successful execution.
Here is the code snippet that I'm using:
import { google } from 'googleapis';
import uuid from 'uuid/v4';
const API_KEY = 'my api key goes here';
google.admin({
version: 'directory_v1',
auth: API_KEY
}).users.list({
customer: 'my_customer',
maxResults: 10,
orderBy: 'email',
}, (err, res: any) => {
if (err) { return console.error('The API returned an error:', err.message); }
const users = res.data.users;
if (users.length) {
console.log('Users:');
users.forEach((user: any) => {
console.log(`${user.primaryEmail} (${user.name.fullName})`);
});
} else {
console.log('No users found.');
}
});
Output:
Login Required
Can someone tell me what I am doing wrong here?
Also, how do I proceed further for listening to the events emitted by the Google API?
---UPDATE---
Here is the snippet that works for me now:
import { JWT } from 'google-auth-library';
import { google } from 'googleapis';
// Importing the serivce account credentials
import { credentials } from './credentials';
const scopes = ['https://www.googleapis.com/auth/admin.directory.user'];
const adminEmail = 'admin_account_email_address_goes_here';
const myDomain = 'domain_name_goes_here';
async function main () {
const client = new JWT(
credentials.client_email,
undefined,
credentials.private_key,
scopes,
adminEmail
);
await client.authorize();
const service = google.admin('directory_v1');
const res = await service.users.list({
domain: myDomain,
auth: client
});
console.log(res);
}
main().catch(console.error);
--- Bonus Tip ---
If you face any Parse Errors while using other methods of the directory, remember to JSON.stringify the request body. For example, on the admin.users.watch method:
// Watch Request
const channelID = 'channel_id_goes_here';
const address = 'https://your-domain.goes/here/notifications';
const ttl = 3600; // Or any other TTL that you can think of
const domain = 'https://your-domain.goes';
const body = {
id: channelID,
type: 'web_hook',
address,
params: {
ttl,
},
};
// Remember to put this in an async function
const res = await service.users.watch({
domain,
customer: 'my_customer',
auth: client, // get the auth-client from above
event: 'add'
}, {
headers: {
'Content-Type': 'application/json'
},
// This is the important part
body: JSON.stringify(body),
});
As you can see in the official documentation, every request sent "to the Directory API must include an authorization token". In order to authorize your request, you have to use OAuth 2.0.
You are providing an API key instead, which is not appropriate for this process. API keys are usually used for accessing public data, not users' private data as in your current situation.
You should follow the steps provided in the Node.js Quickstart instead:
First, obtain client credentials from the Google API Console.
Second, authorize the client: obtain an access token after setting the user credentials and the appropriate scopes (a process accomplish in functions authorize and getNewToken in the Quickstart).
Finally, once the client is authorized, call the API (function listUsers).
Update:
If you want to use a Service Account for this, you will have to follow these steps:
Grant domain-wide delegation to the Service Account by following the steps specified here.
In the Cloud console, create a private key for the Service Account and download the corresponding JSON file. Copy it to your directory.
Use the Service Account to impersonate a user who has access to this resource (an Admin account). This is achieved by indicating the user's email address when creating the JWT auth client, as indicated in the sample below.
The code could be something along the following lines:
const {google} = require('googleapis');
const key = require('./credentials.json'); // The name of the JSON you downloaded
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/admin.directory.user'],
"admin#domain" // Please change this accordingly
);
// Create the Directory service.
const service = google.admin({version: 'directory_v1', auth: jwtClient});
service.users.list({
customer: 'my_customer',
maxResults: 10,
orderBy: 'email',
}, (err, res) => {
if (err) return console.error('The API returned an error:', err.message);
const users = res.data.users;
if (users.length) {
console.log('Users:');
users.forEach((user) => {
console.log(`${user.primaryEmail} (${user.name.fullName})`);
});
} else {
console.log('No users found.');
}
});
Reference:
Directory API: Authorize Requests
Directory API: Node.js Quickstart
Delegate domain-wide authority to your service account
Google Auth Library for Node.js
I hope this is of any help.

How to create Oauth2 with graphql

I am using feathers server and I want to implement Oauth2 authentification with facebook or github strategy or whatever. But I also would like to use with graphql
But I dont know how to implement with graphql I'm using https://github.com/feathersjs/feathers-authentication-oauth2 it works as a API if I send GET request on callback url it works correctly I get token but I'd like do this with graphql as for example in LOCAL or LDAP strategy
const authentication = feathers()
authentication.configure(hooks())
.configure(rest(base).superagent(superagent))
.configure(auth({ storage: localStorage }));
RootMutation: {
signInLocal(root, {email, password}, context){
return authentication.authenticate({
strategy: 'local',
email: email,
password: password
}, context).then(data=>{
// console.log(data)
return data
})
},
signInLdap(root, {username, password}, context){
return authentication.authenticate({
strategy: 'ldap',
username: username,
password: password
}, context).then(data=>{
// console.log(data)
return data
})
}
}
I tried
RootQuery: {
signInGithub(root, data, context){
return authentication.authenticate({
strategy: 'github',
}, context).then(data=>{
console.log(data)
return data
})
}
},
But I got error
feathers-authentication:passport:authenticate 'github' authentication redirecting to https://github.com/login/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgithub
%2Fcallback&scope=user&client_id=0b786a43497059d2a28b 302 +3ms
feathers-authentication:middleware:failure-redirect Redirecting to https://github.com/login/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgithub%2Fcallback&scope=
user&client_id=0b786a43497059d2a28b after failed authentication. +7ms
Error: Unexpected end of JSON input
Thanks for any help

Resources