microsoft graph cant get refresh token - node.js

I am using msal for getting tokens as per below:
const msal = require('#azure/msal-node');
const msalConfig = {
auth: {
clientId: config.MS_CLIENT_ID,
authority: config.AAD_ENDPOINT + 'consumers', //config.TENANT_ID,
clientSecret: config.MS_CLIENT_SECRET,
}
};
const cca = new msal.ConfidentialClientApplication(msalConfig);
const authCodeUrlParameters = {
scopes: ["Mail.ReadWrite"],
redirectUri: config.MS_REDIRECT_URI,
};
// get url to sign user in and consent to scopes needed for application
cca.getAuthCodeUrl(authCodeUrlParameters);
let tokenReq = {
code: ctx.params.Token,
scopes: ["Mail.ReadWrite"],
redirectUri: config.MS_REDIRECT_URI
}
const tokenRes = await cca.acquireTokenByCode(tokenReq);
I am not getting refresh token from acquireTokenByCode method

First to implement refresh token, you need the scope offline_access incorporated in your flow.
That said, Msal-Node des not expose the refresh token. It will use the refresh token internally to renew the access token. Check this thread for more details. You use acquireTokenSilent when you need an access token as Msal will take care of managing the refresh token.

Related

The account does not exist in this organization error during Microsoft SSO

I am trying to do a microsoft sso, where any user can use his microsoft account to sign in to the app. Now, if the user is part of the application users it works perfectly fine, but when I try to log in with my personal one, it gives me an error message saying "The account does not exist in this organization".
My endpoint for the sso:
const REDIRECT_URI = "http://localhost:3000/redirect";
const cca = new msal.ConfidentialClientApplication(config);
const scopes = ["user.read"];
router.get("/auth", (req, res) => {
// Construct a request object for auth code
const authCodeUrlParameters = {
scopes: scopes,
redirectUri: REDIRECT_URI,
};
// Request auth code, then redirect
cca
.getAuthCodeUrl(authCodeUrlParameters)
.then((response) => {
return res.send(response);
})
.catch((error) => res.send(error));
});
router.get("/redirect", (req, res) => {
// Use the auth code in redirect request to construct
// a token request object
const tokenRequest = {
code: `${req.query.code}`,
scopes: scopes,
redirectUri: REDIRECT_URI,
};
// Exchange the auth code for tokens
cca
.acquireTokenByCode(tokenRequest)
.then(async (response) => {
res.send(response);
})
.catch((error) => res.status(500).send(error));
});
It gives me an error message saying, "The account does not exist in this organization".
The error message shows that your personal Microsoft account is not associated with the organization that the application is using for authentication. Microsoft provides two different authentication services: Microsoft Account (MSA) and Azure Active Directory (AAD).
By using Guest method, you can use your personal account by assigning the roles.
If your organization has set up the application to use AAD for authentication, then you need to have an AAD account in the same organization in order to log in.
Create an AAD account and map it with the same email address as your MSA. This will allow you to log into the application using your AAD account.
And if you don't want to create an AAD account, you can use a different email address (such as a work email address) that is already associated with the organization's AAD.
Steps to create Microsoft SSO
Register your application to access Microsoft Graph API, and you need to first register your application in the Microsoft Developer Portal and obtain a client ID and secret.
The first step in the authorization code grant flow is to redirect the user to the Microsoft authorization endpoint. The user must sign in and grant the permissions that your application requests.
After the user grants permission, Microsoft will redirect the user back to your application with an authorization code.
Your application can then exchange this code for an access token by making a POST request to the Microsoft token endpoint.
Once you have an access token, you can use it to call the Microsoft Graph API on behalf of the user. To do this, you'll need to add the access token to the Authorization header of your API request.
Access tokens are short-lived and need to be refreshed after a certain time period. You can use the refresh token to obtain a new access token without requiring the user to sign in again.
async function getAccessToken(code) {
const tokenRequestBody = querystring.stringify({
grant_type: 'authorization_code',
code: code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret,
});
const tokenResponse = await axios.post('https://login.microsoftonline.com/common/oauth2/v2.0/token', tokenRequestBody);
return tokenResponse.data.access_token;
}
async function getUserProfile(accessToken) {
const userProfileResponse = await axios.get('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return userProfileResponse.data;
}
async function main() {
const code = 'AUTHORIZATION_CODE';
const accessToken = await getAccessToken(code);
const userProfile = await getUserProfile(accessToken);
console.log(userProfile);
}
References taken from
Nodejs-webapp-msal
ADD

Is this how to get a refresh token using msal-node library?

I'm using the msal nodejs library. I have the following code
const ouathClient = new msal.ConfidentialClientApplication(msalConfig);
const tokenRequest = {
code: request.query.code,
scopes: process.env.OUTLOOK_OAUTH_SCOPES.split(','),
redirectUri: process.env.DOMAIN_NAME + "/outlook/oauth/redirect",
accessType: "offline"
};
const response = await ouathClient.acquireTokenByCode(tokenRequest);
const accessToken = response.accessToken;
const refreshToken = () => {
const tokenCache = ouathClient.getTokenCache().serialize();
const refreshTokenObject = (JSON.parse(tokenCache)).RefreshToken
const refreshToken = refreshTokenObject[Object.keys(refreshTokenObject)[0]].secret;
return refreshToken;
}
const tokens = {
accessToken,
refreshToken: refreshToken()
}
IS this how to get the refresh token from the msal-node library? I created an app that connects doctors and patients. I want patients to be able to book time on a doctor's outlook calendar. I need to get access to the doctor's outlook account. I can use the access token to get access to his calendar, but that expires.
How do I refresh the token after some time?

How to authenticate Octokit using Github Oauth access_token

I'm building a GitHub Oauth app, and I'm trying to authenticate Octokit using an Oauth access_token that I'm getting when the user clicks sign in with Github.
The access_token I'm using has access to the repo scope, but when I try to authenticate Octokit with this token, I get: HttpError: A JSON web token could not be decoded
Here is my code:
let TOKEN = "<Token>"
const appOctokit = new Octokit({
auth: TOKEN
});
I've also tried authenticating like this:
const appOctokit = new Octokit({
authStrategy: createOAuthAppAuth,
auth: {
clientId: "<Client_ID>",
clientSecret: "<Client_Secret>",
},
});
but when I do that, and I try deleting an issue using octokit, I get an HttpError: Not Found error.

Chrome Extensions - token from "launchWebAuthFlow" expires after an hour and need user interaction to get new one

I am using launchWebAuthFlow in a service worker to authenticate users who choose to backup the extension settings in their Google Drive.
When a user clicks the login button, it sends a message to the service worker (MV3, perviously "background script"), who does this:
const redirectUrl = await browser.identity.launchWebAuthFlow({
'url': _createAuthEndpoint(),
'interactive': true
})
const url = new URL(redirectUrl);
const urlParams = new URLSearchParams(url.hash.slice(1));
const params = Object.fromEntries(urlParams.entries());
await browser.storage.local.set({googleToken: params.access_token});
Helper method to construct auth url:
function _createAuthEndpoint() {
const redirectURL = browser.identity.getRedirectURL();
const { oauth2 } = browser.runtime.getManifest();
const clientId = oauth2.client_id;
const authParams = new URLSearchParams({
client_id: clientId,
response_type: 'token',
redirect_uri: redirectURL,
scope: 'openid ' + oauth2.scopes.join(' '),
});
return `https://accounts.google.com/o/oauth2/auth?${authParams.toString()}`;
}
It works well for about an hour, after that the token get invalidated and I need to get a new token. If i try to use launchWebAuthFlow with interactive: false I get an error "user interaction required"
Is there a way to have the token refresh without user interaction?

Refresh token for Google APIs to keep user logged in

I am developing an App on Actions on Google that uses Google Calendar. At the start of a user's first interaction, they are prompted to link their Google account for access to the calendar. But then for nearly every future interaction, the user has to authenticate again.
My code to get the access token from the user data is below. I'm not sure if there's a way to get the refresh token to add to the credentials. I've seen you should include "access_type": "offline" in the request in other answers, but I'm not sure where I'd put it in my code. Any help would be greatly appreciated!
const googleAuth = require('google-auth-library');
function getAuth(app) {
var accessToken = app.getUser().accessToken;
var clientId = CLIENT_ID;
var clientSecret = CLIENT_SECRET;
var redirectUrl = 'https://oauth-redirect.googleusercontent.com/r/my_app_name';
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
var token = {
"access_token": accessToken,
"refresh_token": "",
"access_type": "offline", //Not sure if these attributes should be here
"approval_prompt": "force",
"immediate": true,
"token_type": "Bearer"
};
oauth2Client.credentials = token;
return oauth2Client;
}
calendar.freebusy.query ({
auth: getAuth(app), //need a Google OAuth client here for API request
headers: { "content-type" : "application/json" },
resource:{
items: [
{
id: "primary"
}
],
timeMin: startDate.format(),
timeMax: endDate.format(),
timeZone: timeZoneId
}, function(err, response) {
console.log('Success!');
}
});
Not sure if this helps, but on the very first interaction a user has to select an account and agree to the calendar permission, but on subsequent interactions they just have to tap "link account to Google" and it automatically authenticates them.
EDIT:
This is a screenshot of the prompt I get on every new interaction with the app. It was my understanding that account linking is only done on the very first interaction with the app, then the accounts are linked for good and the user need not be prompted again. I am not receiving any errors, I was just wondering if and how I can modify my current code to not prompt the user to link their account on every single interaction.

Resources