nodejs+express+passport-gitlab2を使ってOAuth Applicationを作る

# はじめに
gitlabはオンプレで独自に構築してます。
認証作るのめんどくさいな。gitlabでいいじゃん。
という事で、OpenIDでの認証+OAuthで認可もできるようにしよう！

と、フロントエンド初心者がハマりつつ実装した記録です。

## passport-gitlab2
これです。
https://www.npmjs.com/package/passport-gitlab2


## 事前準備
gitlab側でつなぐ準備しておきます。
【Admin Area】→【Applications】のところで設定します。

- アプリケーション名の入力
- OAuthでのコールバックURLの入力
![image.png](https://qiita-image-store.s3.amazonaws.com/0/268550/cfd4212a-79ef-3199-0cb6-8edfb4168bf1.png)

## 結果

こうなる。

まずは依存情報の追加。

```javascript:requiredの追加
var passport = require('passport');
var session = require('express-session');
var GitLabStrategy = require('passport-gitlab2').Strategy;
```

次に、セッション有効化のための定義記載。

```javascript:session管理のための設定
app.use(session({
  secret: "secret-key",
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: false,
    secure: true,
    maxage: 1000 * 60 * 30
  }
}));
app.use(passport.initialize());
app.use(passport.session());
```

次に、認証するURL、コールバックURLの定義を記載。

```javascript:認証するための設定
app.get('/', passport.authenticate('gitlab'));
app.get('/auth/gitlab/callback',
  passport.authenticate('gitlab', {
    failureRedirect: '/error.html'
  }),
  function (req, res) {
    // Successful authentication, redirect home.
    res.redirect('/home');
  });
```

そして、gitlabからの認証時の戻りの処理と、deserialize/serialize処理を定義。
`done` 

```javascript:passport関連の定義
//passport
passport.use(new GitLabStrategy({
  clientID: process.env.GITLAB_APP_ID,
  clientSecret: process.env.GITLAB_APP_SECRET,
  callbackURL: process.env.GITLAB_CALLBACK,
  baseURL: process.env.GITLAB_URL
},
  function (accessToken, refreshToken, profile, done) {
    if (profile) {
      user = profile;
      return done(null, { id: profile.id });
    }
    else {
      return done(null, false);
    }
  }
));
passport.deserializeUser(function (id, done) {
  console.log('Deserialize user called.');
  return done(null, { "id": id });
});
passport.serializeUser(function (user, done) {
  console.log('Serialize user called.');
  return done(null, { id: user.id });
});
```

後は、各種routeに対して認証が必須のように定義する。

```javascript:ensureAuthenticatedからパススルーするように変更
function ensureAuthenticated(req, res, next) {
  console.log("ensureAuthenticated");
  if (req.isAuthenticated())
    return next();
  else
    res.redirect('/');
}

router.get('/home', ensureAuthenticated, function (req, res, next) {
  res.send("OK");
})
```


# ハマったところ

## User is not define

公式にこう書いてるから、なるほどなるほど。よし、コピペだ！

```
passport.use(new GitLabStrategy({
    clientID: GITLAB_APP_ID,
    clientSecret: GITLAB_APP_SECRET,
    callbackURL: "http://localhost:3000/auth/gitlab/callback"
  },
  function(accessToken, refreshToken, profile, cb) {
    User.findOrCreate({gitlabId: profile.id}, function (err, user) {
      return cb(err, user);
    });
  }
));
```

動かしてみると、 `User is not defined.` と動きません。
https://github.com/auth0/passport-windowsauth/issues/37

## 無限に認証のリダイレクトループ発生

```
var session = require('express-session');
・・・
app.use(passport.session());
```

そもそもsession使わないと、上手く連携できないよって話。

## あれ？認証しなくても動いちゃう…

interceptor?的なもんが勝手にやってくれると思ったけど、やってくれない。
自分でちゃんとパス毎に設定してあげないと！
※通常は、routerを拡張するのかなぁー。

```javascript:ensureAuthenticatedからパススルーするように変更
//認証チェック
function ensureAuthenticated(req, res, next) {
  console.log("ensureAuthenticated");
  if (req.isAuthenticated())
    return next();//認証チェックしてから、次を呼び出すよ。
  else
    res.redirect('/');
}

router.get('/home', ensureAuthenticated, function (req, res, next) {
  res.send("OK");
})
```

## なんか…思った画面と違う
OAuthってあのGoogleのような認証して、「このアクセス許可与えますけど良いですか？」画面が出るはずなんだけど、出ない。
ただのログイン画面が出てくるだけ。さみしい。

でも、まぁ・・・こういうもんだろうと思って放置しました。

## そもそもpassport知る必要がある。

http://www.passportjs.org/packages/passport-npm/
これ前提で動く。`passport-gitlab2`は、このOAuthのService Providerのライブラリなだけ。
なので、そもそもpassportがどう動くのか知る必要がある。