1

「passport-azure-ad-oauth2」 npm モジュールを使用してアクセス トークンを取得し、それを MS Graph API に渡すことができます。

passport.use(new AzureAdOAuth2Strategy({
    clientID: process.env.OUTLOOK_CLIENT_ID,
    clientSecret: process.env.OUTLOOK_SECRET,
    callbackURL: '/auth/outlook/callback',
},
    function (accesstoken: any, refresh_token: any, params: any, profile, done) {
        logger.info('Completed azure sign in for : ' + JSON.stringify(profile));
        logger.info('Parameters returned: ' + JSON.stringify(params));
        const decodedIdToken: any = jwt.decode(params.id_token);
        logger.info('Outlook Access Token:' + accesstoken);
        logger.info('Decoded Token: ' + JSON.stringify(decodedIdToken, null, 2));

        process.env['OUTLOOK_ACCESS_TOKEN'] = accesstoken;
        // add new user with token or update user's token here, in the database

    }));

次に、'@microsoft/microsoft-graph-client' npm モジュールを使用して、次のようにグラフ API からカレンダー イベントをフェッチします。

try {
    const client = this.getAuthenticatedClient(process.env['OUTLOOK_ACCESS_TOKEN']);
    const resultSet = await client
                .api('users/' + userId + '/calendar/events')
                .select('subject,organizer,start,end')
                .get();
    logger.info(JSON.stringify(resultSet, null, 2));
} catch (err) {
    logger.error(err);
}

getAuthenticatedClient(accessToken) {
    logger.info('Using accestoken for initialising Graph Client: ' + accessToken);
    const client = Client.init({
        // Use the provided access token to authenticate requests
        authProvider: (done) => {
            done(null, accessToken);
        }
    });

    return client;
}

ただし、成功したログインで提供された accessToken を使用すると、次のエラーが発生します: CompactToken の解析がエラー コードで失敗しました: 80049217

私が間違って何をしているのですか?

更新:これらは私が使用しているスコープです:「openid、profile、offline_access、calendars.read」

更新:スコープを少し編集した後、次のエラーが表示されます:無効なオーディエンス。

jwt.ms で受信したトークンをデコードすると、「aud」の値は次のようになります: "00000002-0000-0000-c000-000000000000"

Passport-azure-ad-oauth2が MS Graph API のトークンを取得するための間違ったライブラリであるということですか?

4

6 に答える 6

1

私のテストによると、次のコードを使用してアクセス トークンを取得できます。app.js

require('dotenv').config();
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var session = require('express-session');
var flash = require('connect-flash');
var passport = require('passport');
var OIDCStrategy = require('passport-azure-ad').OIDCStrategy;


// Configure simple-oauth2
const oauth2 = require('simple-oauth2').create({
  client: {
    id: process.env.OAUTH_APP_ID,
    secret: process.env.OAUTH_APP_PASSWORD
  },
  auth: {
    tokenHost: process.env.OAUTH_AUTHORITY,
    authorizePath: process.env.OAUTH_AUTHORIZE_ENDPOINT,
    tokenPath: process.env.OAUTH_TOKEN_ENDPOINT
  }
});
var users = {};

// Passport calls serializeUser and deserializeUser to
// manage users
passport.serializeUser(function(user, done) {
  // Use the OID property of the user as a key
  users[user.profile.oid] = user;
  done (null, user.profile.oid);
});

passport.deserializeUser(function(id, done) {
  done(null, users[id]);
});

// Callback function called once the sign-in is complete
// and an access token has been obtained
async function signInComplete(iss, sub, profile, accessToken, refreshToken, params, done) {
  if (!profile.oid) {
    return done(new Error("No OID found in user profile."), null);
  }


  // Create a simple-oauth2 token from raw tokens
  let oauthToken = oauth2.accessToken.create(params);

  // Save the profile and tokens in user storage
  users[profile.oid] = { profile, oauthToken };
  return done(null, users[profile.oid]);
}

// Configure OIDC strategy
passport.use(new OIDCStrategy(
  {
    identityMetadata: `${process.env.OAUTH_AUTHORITY}${process.env.OAUTH_ID_METADATA}`,
    clientID: process.env.OAUTH_APP_ID,
    responseType: 'code id_token',
    responseMode: 'form_post',
    redirectUrl: process.env.OAUTH_REDIRECT_URI,
    allowHttpForRedirectUrl: true,
    clientSecret: process.env.OAUTH_APP_PASSWORD,
    validateIssuer: false,
    passReqToCallback: false,
    scope: process.env.OAUTH_SCOPES.split(' ')
  },
  signInComplete
));

詳細については、ドキュメントおよびサンプルを参照してください。

于 2019-11-04T02:45:44.160 に答える
0

受け入れられた回答は、OP のケースである特定の Passport-azure-ad-oauth2 npm モジュールを使用している人々にのみ役立ちますが、タイトルは、Microsoft Graph で作業しているときにこのエラーが発生した場合に一般的です。有効なアクセス トークンの代わりに Authorization ヘッダーに更新トークンを (誤って) 渡して Graph に接続しようとすると、次のエラーが発生します。

GET https://graph.microsoft.com/v1.0/me Authorization: Bearer wronglySuppliedRefreshTokenHere

アクセス トークンの有効期限が切れているため、リフレッシュ トークンが機能することを期待して、これを試した人もいるかもしれません。

更新トークンを使用して有効な認証トークンを取得するには、http POST 要求を行う必要があります。

https://login.microsoftonline.com/{yourTenantId}/oauth2/v2.0/tokenrequest

(1) Authorization ヘッダーを使用すると、次のようになります。

承認: Bearer {yourExpiredAccessToken}

(2) 次のような Content-Type ヘッダー:

コンテンツ タイプ: application/x-www-form-urlencoded

(3) 次のようなキーと値のペア (値が urlencode されている) を含む本文 (中括弧を除外し、中括弧内の変数を実際の値に置き換えます)...

client_id={yourClientId}&grant_type=refresh_token&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2FUser.Read&client_secret={yourClientSecret}&refresh_token={yourRefreshToken}

scope の値は単なる例であることに注意してください。最初にアクセス トークンとリフレッシュ トークンを要求したときに使用したのと同じスコープを使用する必要があります。

リクエストを送信すると、認証ベアラー ヘッダーで使用できる有効なアクセス トークンを含む json レスポンスが返され、正常に接続できるようになります。

また、アクセス トークンの有効期限が切れているときにリクエストを行うたびに、ServiceException ("code":"InvalidAuthenticationToken", "message":"Access token has expired or is not yet valid.") をキャッチする必要があることに注意してください。grant_type=refresh_token を指定して POST を再送信することで処理し、ヘッダーを新しい認証トークンで再度更新して、再試行してください。

于 2021-11-05T15:19:12.770 に答える
0

古い「Bearer」+トークンの代わりに、authenticationProviderにaccessTokenだけを渡してこれを解決しました:例:

TokenCredential tokenCredential = tokenRequestContext -> Mono.just(new AccessToken(accessToken, OffsetDateTime.MAX));
IAuthenticationProvider authenticationProvider = new TokenCredentialAuthProvider(tokenCredential);
于 2021-04-18T14:10:52.083 に答える