2013-11-23 20 views
32

Mam sporo czasu tutaj próbując użyć Google OAuth do uwierzytelniania użytkowników w mojej aplikacji ekspresowej węzła. Mogę z powodzeniem zrobić OAuth, która zwraca odpowiedź w taki sposób:Jak mogę odszyfrować Google OAuth 2.0 JWT (OpenID Connect) w aplikacji węzła?

{ 
    access_token: 'token string', 
    id_token: 'id.string', 
    expires_in: 3599, 
    token_type: "Bearer" 
} 

To wszystko ma sens, ale nie mogę dla życia mnie dowiedzieć się, jak zdekodować JWT. W tym wszystkim jestem trochę niedoświadczony, więc to wszystko jest dla mnie trochę obce.

Postępując zgodnie z instrukcjami podanymi tutaj: https://developers.google.com/accounts/docs/OAuth2Login#validatinganidtoken Próbuję odszyfrować lokalny plik JWT lokalnie w aplikacji mojego węzła.

Zainstalowałem https://github.com/hokaccha/node-jwt-simple w środowisku mojego węzła.

I jestem prawie pewien, że muszę użyć tego certyfikatu (https://www.googleapis.com/oauth2/v1/certs) w jakiś sposób, aby go rozszyfrować, ale jestem tu trochę stratny. Naprawdę nie rozumiem, jak mogę uzyskać certyfikat do mojej aplikacji węzła, a następnie jak go używać z węzłem-jwt-proste. I tak naprawdę nie rozumiem, skąd wiem, kiedy muszę pobrać nowy certyfikat, zamiast używać buforowanego.

Ktoś tam z pewnym doświadczeniem w tej dziedzinie może mi pomóc?

Dzięki za pomoc. W tej chwili jestem całkowicie zagubiony.

** Aktualizacja **

Więc zrobiłem jakiś postęp ... Rodzaju. Wywołując jwt.decode (id_token, certificate, true); Potrafię pomyślnie zdekodować token. Nawet jeśli var certyfikatu jest pustym obiektem {}. Pozostawia mi to jeszcze 3 pytania. 1: Jaki jest najlepszy sposób uzyskania certyfikatu w mojej aplikacji ekspresowej przy użyciu adresu URL z google? 2: Skąd mam wiedzieć, kiedy muszę pobrać nową wersję? 3: Wydaje się, że przekazywanie w true dla noVerify (3 arg w jwt.decode) jest okropnym pomysłem. Jak mogę to uruchomić, nie przekazując tego? Wygląda na to, że jwt-simple spodziewa się hs256, a token używa rs256.

Ponownie, jestem super niedoświadczony w tym, więc mogę być daleko poza bazą tutaj.

* AKTUALIZACJA * Dzięki pomocy Nat, udało mi się sprawić, że to działa! Myślę, że wypróbowałem każdy pojedynczy moduł węzła JWT i JWS tam. W końcu wylądowałem na: Zauważyłem, że żaden z modułów, na które patrzyłem, nie spełnił moich oczekiwań. Stworzyłem następujące metody pomocnicze dekodujące jwt, które używam do dekodowania id_token, więc mogę pobrać dziecko z nagłówka.

module.exports = { 
    decodeJwt: function (token) { 
    var segments = token.split('.'); 

    if (segments.length !== 3) { 
     throw new Error('Not enough or too many segments'); 
    } 

    // All segment should be base64 
    var headerSeg = segments[0]; 
    var payloadSeg = segments[1]; 
    var signatureSeg = segments[2]; 

    // base64 decode and parse JSON 
    var header = JSON.parse(base64urlDecode(headerSeg)); 
    var payload = JSON.parse(base64urlDecode(payloadSeg)); 

    return { 
     header: header, 
     payload: payload, 
     signature: signatureSeg 
    } 

    } 
} 

function base64urlDecode(str) { 
    return new Buffer(base64urlUnescape(str), 'base64').toString(); 
}; 

function base64urlUnescape(str) { 
    str += Array(5 - str.length % 4).join('='); 
    return str.replace(/\-/g, '+').replace(/_/g, '/'); 
} 

Używam tego dekodowanie celu ustalenia, czy muszę ciągnąć w nowym cert publicznej od: https://www.googleapis.com/oauth2/v1/certs

Następnie używam że cert publicznego i Węzeł-ŚJ (https://github.com/brianloveswords/node-jws) jws.verify (id_token , cert) w celu weryfikacji podpisu!

Brawo! Jeszcze raz dziękuję za dodatkowe wyjaśnienie udzielone w odpowiedzi. To pomogło mi zrozumieć, co nawet próbowałem zrobić. Mam nadzieję, że to może pomóc także innym.

Odpowiedz

48

Z punktu widzenia specyfikacji, napotykamy [Łącze OpenID].

id_token to podpis [JWS] [JWT]. W tym przypadku jest to "." oddzielony ciąg z trzema składnikami. Pierwsza część to nagłówek. Drugi to ładunek. Trzeci to podpis. Każdy z nich jest zakodowany w standardzie Base64url.

Podczas dekodowania nagłówka, otrzymasz coś takiego:

{ "ALG": "RS256", "dziecko": "43ebb53b0397e7aaf3087d6844e37d55c5fb1b67"}

W "ALG" wskazuje, że algorytm podpisu to RS256, który jest zdefiniowany w [JWA]. "Dziecko" wskazuje kluczowy identyfikator klucza publicznego, który odpowiada kluczowi używanemu do podpisania.

Teraz jestem gotowy odpowiedzieć na niektóre pytania:

2: Skąd będę wiedzieć, kiedy trzeba ciągnąć w świeżej wersji tego?

Gdy plik potomny zbuforowanego pliku certyfikatu (plik [JWK]) nie pasuje do elementu potomnego w nagłówku, pobierz nowy plik certyfikatu. (BTW, adres URL, z którego można wyciągnąć z certyfikatów są nazywane x5u.)

3: Wydaje się, przechodząc w prawdziwe dla noVerify (3rd argumentu w jwt.decode) jest fatalny pomysł. Jak mogę to uruchomić, nie przekazując tego w postaci ?

Rzeczywiście. Być może warto przyjrzeć się innej bibliotece, takiej jak kjur.github.io/jsjws/.

Odniesienia

  • [OpenID Connect] openid.bitbucket.org/openid-connect-core-1_0.html
  • [JWS] tools.ietf.org/html/draft-ietf- Jose JSON internetowej podpis
  • [JWT] tools.ietf.org/html/draft-ietf-oauth-json-web-token
  • [JWK] tools.ietf.org/html/draft-ietf -oauth-json-web-keys
  • [JWA] tools.ietf.org/html/draft-ietf-j ose-json-web-algorithms
+0

Awesome! Dziękuję bardzo za dokładne i szczegółowe wyjaśnienie. Pomogło to ogromnie w moim zrozumieniu tego, co nawet próbowałem zrobić. A teraz wiem, czego powinienem szukać, jeśli mam więcej pytań. Bardzo to doceniam. – ThePuzzleMaster