å®å šã«åå¿è ã®è¶£å³ã§ããå€åå ãæå±ããå£äœã®æŽ»åãšã¯é¢ä¿ãããŸããã
tl;dr
- OpenID Connect(OIDC) ã§ãã°ã€ã³ãããSingle Page App(SPA) ãã©ããNode.jsã§äœããŸããã
- äœã£ãSPAãã©ãã§ãAuth0ãå©çšããŠã¿ãŸããããµã€ã³ã¢ãããããAuth0ã䜿ã£ããã°ã€ã³å®äºãŸã§ãåèŠã§12åã§çµãããŸããã
- äžå¿å©çšèŠçŽãç°¡åã«ç®ãéããã
- äžçªè¿·ã£ãã®ã¯ç¡æãµã€ã³ã¢ãããŸã§ã®ã«ãŒãã
- äœã£ãSPAãã©ãã®è§£èª¬ã¯åŸåã§ãã
- Google IDã§ãã°ã€ã³ããããã®èšå®ãæåŸã«ã
詊ããŠã¿ã
Google IDãã°ã€ã³ã§ãããGlitchã«ããµã³ãã«ãã¢ããããŸããã
ãŸãã¯å®éã«åãããŠã¿ã
Node.jsãlocalhostã§åãç°å¢ãåæã§ããïŒlocalhostãããªããšãã¯localhostã£ãŠæžããŠããéšåãé©åœã«å€ããŠãã ããïŒ
Auth0ã®ãµã€ã³ã¢ãã
Googleæ€çŽ¢ã§ãAuth0ããšå
¥ããŠãåºåã®äžã®ãªã³ã¯ãã¯ãªãã¯ããŸãã

åºåã®ãªã³ã¯ãã¯ãªãã¯ãããšããµã€ã³ã¢ããããŒãžã«ãã©ãçããŸããã
å³äžã®ãç¡æãã©ã€ã¢ã«ããã¯ãªãã¯ããŠãGitHubã§ããGoogleã§ãã奜ããªã¢ã«ãŠã³ãã§ãµã€ã³ã¢ããããŸãã
ããããã°èªåã®ååããå
¥åããŠããªãæ°ãããã
ãµã€ã³ã¢ãããçµãã£ãããããããã·ã¥ããŒãã衚瀺ãããŸãã
å³äžã®ããïŒCreate Applicationããã¯ãªãã¯ããŸãã
é©åœã«ã¢ããªåãèããŠãããä»åã¯ãRegular Web ApplicationsããéžæããŸãã
å€åãããã¯äœãéžãã§ã倧äžå€«ãªæ°ãããŸãã

次ã®ç»é¢ã§ããQuick StartããåºãŸãããããã¯äœ¿ããããã®é£ã®ãSettingsãã¿ããéãã
ãClient IDãããClient Secretãã確èªããŸããïŒåŸã§ã³ããããŸããïŒ

äžã«ã¹ã¯ããŒã«ããŠãã£ãŠããApplication URIsãã®äžã®ããAllowed Callback URLsãã«ã http://localhost:3000/ ãšå
¥åããŸãã

ããã«äžã«ã¹ã¯ããŒã«ããŠãã£ãŠããAdvanced SettingsããéããŸãã
äžçªå³ã®ãEndpointsããã¯ãªãã¯ããŸãã
ãã®äžã®ããOAuth Authorization URLããšããOAuth Token URLãããåŸã§ã³ããããŸãã

Node.js ã³ãŒãã®ããŠã³ããŒããšèšå®
äžèšã®ã¬ããžããªããã§ãã¯ã¢ãŠãããŸããé¢åãªãããããããœãŒã¹ã®ZIPãçŽæ¥ããŠã³ããŒãããŸãã
ãã¡ã€ã«ãè§£åããããã¿ãŒããã«ããããã¯ã³ãã³ãããã³ããã§npm install ãå®è¡ããŸãã
åŠçãåŸ
ã£ãŠããéã«ã.env.exampleããšãã£ã¿ã§éããå
ã»ã©Auth0ã®èšå®ããŒãžã§èŠã€ããã
ãOAuth Authorization URLãããOAuth Token URLãããClient IDãããClient Secretãããããããã³ãããããã.envãšããŠä¿åããŸãã
èµ·å
node app.js ãå®è¡ããŸãã
å®éã«ãã°ã€ã³ããŠã¿ã
ãã©ãŠã¶ã§ã http://localhost:3000 ã«ã¢ã¯ã»ã¹ããŸãã
äžããé ã«ãïŒ1ïŒãïŒ2ïŒã®ãã¿ã³ãæŒããŠãããšãAuth0ã®ãã°ã€ã³ããŒãžã«è¡ããŸãã

ãSign upããããeã¡ãŒã«ãšãã¹ã¯ãŒããå
¥åããŠãã°ã€ã³ããããšãã§ããŸãããããã©ã«ãã§Googleãã°ã€ã³ã䜿ããããã«èšå®ãããŠããŸãã

ãAcceptããæŒããšãå
ã®ããŒãžã«æ»ã£ãŠããŸãã

(3)ãæŒããšãNode.jsçµç±ã§ãAuth0ã®ãµãŒãããããŠãŒã¶æ
å ±ïŒããããIDããŒã¯ã³ïŒãååŸããŠããã®äžèº«ããã³ãŒãããŠè¡šç€ºããŸãã

ãããŸã§å®æž¬12åã§çµãã£ãŠããŸããŸããããå§ãããšãã¯ãã¿ã€ã ã¢ã¿ãã¯ããã€ãããªããŠãªãã£ãã®ã§ãçµãã£ãŠããæèšãèŠãŠã³ã£ããããŸãããæåã®ãµã€ã³ã¢ããããŒãžã«è¿·ã£ãããå©çšèŠçŽãèªãã ãããªããã°ãæ¬åœã«3åã§çµãã£ãããããªãããšæããŸãã
SPAãã©ãã®äœãæ¹
äœã£ãçç±
ããããæ®éã®Webãµã€ãã§ãGoogleãFacebook,Twitterãªã©ã䜿ã£ããœãŒã·ã£ã«ãã°ã€ã³ãå®çŸããäŸã¯ããèŠãã®ã§ããããã€ãã£ãã¢ããªã§ã®ãœãŒã·ã£ã«ãã°ã€ã³ã¯ãåãµãŒãã¹ãSDKãæäŸããŠãããããä»çµã¿ãããããããããã©ãã¯ããã¯ã¹ã«ãªã£ãŠããŸã£ãŠããæ°ãããŸããã
ãªã®ã§ããã€ãã£ãã¢ããªãäœãã®ã¯ã¡ãã£ãšé£æåºŠé«ãã§ãããéçãªHTML+JavaScriptã§ããµãŒããšã¯REST APIã§éä¿¡ããŠããã€ãã£ãã¢ããªã£ãœãæ¯ãèããSPAãã©ããäœãããšã§ãä»çµã¿ãçè§£ããããšæããŸããã
åèã«ãããµã€ã
æ¥æ¬ã«ãããOpenID Connectã®éé®ã®ãäºæ¹ã®ããã°ãåèã«ã¢ãŒããã¯ãã£ãèããŸããããã€ããäžè©±ã«ãªã£ãŠãããŸãã
ã¢ãŒããã¯ãã£
REST APIã£ãœãäœãããã£ãã®ã§ãç°¡åã«ã§ããNode.js + Expressæ§æã䜿ããŸãã
SPAéšåã¯ãJavaScriptãå«ããŠ1ã€ã®HTMLãã¡ã€ã«ã«ããŠããŸãã
ïŒäœãå§ãããšãã¯ãäžéšåçãªéšåãããããªãšãejsã䜿ããŸããããçµæçã«å®å
šã«éçãªããŒãžã«ãªã£ãŠããŸããïŒ
OpenID Connectã§SPAãäœãå Žåãã€ã³ããªã·ãããããŒããã€ããªãããããŒã§ãSPAãçŽæ¥IDããŒã¯ã³ãååŸãããã¿ãŒã³ããã玹ä»ãããŠããèš³ã§ãããIDããŒã¯ã³ã«ããããªãã«å人æ å ±ãå«ãŸããå Žåãããããšãšãå®è£ ãã·ã³ãã«ã«ããããã«ããµãŒããSPAéã¯ã»ãã·ã§ã³IDã§ç®¡çããããšã«ããŸããã
ãã°ã€ã³ã®ãããŒã¯ãããªæãã§ãã(1)ãã(3)ã¯ãããããå®éã®SPAãã©ãã䜿ããšãã«æŒããã¿ã³ã«å¯Ÿå¿ããŠããŸãã
éåžžWebãµã€ãã§ããã°ããŠãŒã¶ã®ãã°ã€ã³ç¶æ
ã¯ã»ãã·ã§ã³IDãCookieã«ä¿åããããšã§ç®¡çããŸãã
ã§ããããã€ãã£ãã¢ããªãæ³å®ããŠãã»ãã·ã§ã³IDã¯AuthorizationããããŒã«å
¥ããããšã«ããŸããããã©ãŠã¶å
ã§ã¯localStorageã«ä¿åããŸãã
ããããèšèšã§æ¬åœã«åé¡ãªãã®ãã¯ãèè ã®ã¢ããã€ã¹ãé æŽããããšããã§ããç§ã¯åå¿è ãªã®ã§ã
ååŠçã®è§£èª¬
(1) ãã°ã€ã³ãªã¯ãšã¹ã
SPAã¯éçãªHTMLã§ããµã€ããéããæç¹ã§ã¯ã»ãã·ã§ã³IDã¯ä»äžããŠããŸããã
Ajaxã§ããµãŒãã«å¯ŸããŠãã»ãã·ã§ã³IDã®æãã ããšãIDP(ID Provider:èªèšŒãµãŒããããã§ã¯Auth0)ã«ãã°ã€ã³ããããã®Authorizationãšã³ããã€ã³ãã®URLãããã©ã¡ãŒã¿ãååŸããŸãã
â» ããã§Authorizationãšã³ããã€ã³ãã®URLãååŸããŠããã®ã§ãäŸãã°IDPãAuth0ããGoogleã«åãæ¿ããå ŽåãããµãŒãåŽã®èšå®ãåãæ¿ããã ãã§ãSPA(HTML/JavaScript)åŽã®ä¿®æ£ã¯äžèŠã«ãªããŸãã
ã€ãã§ã«ãSPAåŽã§ããCSRFããé²åŸ¡ãããããstateãšããä¹±æ°ãçæããŠãããŸãã
ãµãŒãåŽã§ã¯ãããã§ã»ãã·ã§ã³IDãæãåºãããã°ã€ã³ã®ããã®PKCEã³ãŒããçæããŠãåçš®ãã©ã¡ãŒã¿ãšãšãã«SPAã«è¿åŽããŸãã
PKCEã«ã€ããŠã®èª¬æã¯ãã¡ã
ãµãŒãããè¿ã£ãŠããã»ãã·ã§ã³IDã¯ãåŸã§äœ¿ãã®ã§localStorageã«ä¿åããŠãããŸãã
ä»åäœã£ãSPAã§ã¯ããã¢çšã«ã»ãã·ã§ã³IDã衚瀺ããŠããŸãããéåžžã¯é ããŠããã¹ãã§ãã
(2) ãã°ã€ã³ããŒãžã«æ¥ç¶
(1)ã§ãµãŒãããè¿ã£ãŠãã Authorizationãšã³ããã€ã³ãã®URLãšãã©ã¡ãŒã¿ã«ãSPAã§çæããStateããã£ã€ããŠãã¢ã¯ã»ã¹ããŸãã
ãã€ãã£ãã¢ããªã§ããã°ãå€éšãã©ãŠã¶ãCustomTab, SFSafariViewControllerãASWebAuthenticationSessionã䜿ããŸãããä»åã¯ãã©ãŠã¶ãªã®ã§åçŽã«location.hrefã§ç§»åããããšã«ããŸãã
é·ç§»å
ã§ç¡äºãã°ã€ã³ãæåãããšãå
ã®ããŒãžã«ãã¯ãšãªãã©ã¡ãŒã¿ãcodeããšãstateããä»å±ããŠè¿ã£ãŠããŸãã
ãã€ãã£ãã¢ããªã§ããã°ãAndroid App LinksãUniversalLinksã䜿ã£ãŠã¢ããªã«åŠçãæ»ãããšãæšå¥šãããŸãã詳现ã¯BCP212/RFC8252ãåç
§ããŠãã ããã
ä»åäœã£ãSPAã§ã¯ããšã©ãŒåŠçã¯çç¥ããŠããŸãã
(3) èªå¯ã³ãŒããšã»ãã·ã§ã³IDéä¿¡
SPAã«èªå¯ã³ãŒãïŒcode )ãšstateãè¿ã£ãŠããã®ã§ããŸããstateãäºåã«ä¿åããŠãããå€ãšäžèŽããããæ€èšŒããŸããããäžèŽããªãã£ãããæªæãã人ããã®æ»æã®å¯èœæ§ããããŸãã
â» ãšãã£ãŠããPKCEã䜿ã£ãŠããéãããã®å
ã®åŠçãæåããªãã®ã§ãŠãŒã¶æ
å ±ã®æµåºãªã©ã®å¯èœæ§ã¯äœãã§ãããstateã䜿ããã«ãcodeãæ»ã£ãŠãããèªåã§ãµãŒãã«éä¿¡ããŠãã°ã€ã³ã詊ã¿ããããªåŠçãããŠãããšãåæã«ãã°ã¢ãŠãããã¡ãã£ããããããªãã®ã§ãæ€èšŒåŠçãå
¥ããŠãããæ¹ããããšæããŸãã
state ãäžèŽããŠãããããªãããµãŒãã«ãèªå¯ã³ãŒããéä¿¡ããŸãããã®éã(1)ã§ä¿åããŠãããã»ãã·ã§ã³IDããAuthorizationããããŒã«ä»äžããŸãã
ä»åäœã£ãSPAã§ã¯ããã¢ã®ããã«ã(3)ã®åŠçãæåã§è¡ãããã«ããŠããŸãããæ¬æ¥ã§ããã°ãèªå¯ã³ãŒããIDPããæ»ã£ãŠããŠãããStateãæ¯èŒãããµãŒãã«éãäžé£ã®åŠçã¯èªåã§è¡ãã¹ãã§ãã
èªå¯ã³ãŒããåä¿¡ãããµãŒãã¯ãã»ãã·ã§ã³IDãšçŽä»ããŠä¿åããŠãããPKCEã³ãŒããšãã¯ã©ã€ã¢ã³ãID/ã¯ã©ã€ã¢ã³ãã·ãŒã¯ã¬ãããèªå¯ã³ãŒããIDP(Auth0)ã«å¯ŸããŠéä¿¡ããŸãã
ãããšãIDPãããIDããŒã¯ã³ãè¿ã£ãŠããŸãã
IDããŒã¯ã³ããã³ãŒããããšããŠãŒã¶IDïŒsubå€)ããããã®ã§ããµãŒãã®äžã§ã¯ãsubå€ãããŒã«ããŠãŠãŒã¶ã管çããŸãã
ãµãŒãå
ã§ãã»ãã·ã§ã³IDãšãsubå€ãçŽä»ããŠããŒã¿ããŒã¹ã«ä¿åãããããã°ã€ã³å®äºã§ãã
SPAã§ã¯ããã¢ã®ãããIDããŒã¯ã³ã®äžèº«ãè¿åŽããŠããŸãã
(4) ã»ãã·ã§ã³IDã®å©çš
ä»ãŸã§ã®åŠçã§ãã»ãã·ã§ã³IDãšãŠãŒã¶ãçŽä»ããã®ã§ãã»ãã·ã§ã³IDãå®å
šã«ç®¡çãããŠããéããã»ãã·ã§ã³IDã®éãäž»ïŒãã®ãŠãŒã¶ã§ãããšããããšãåæã«ãµãŒãã¹ãæäŸããŸãã
ä»åäœã£ãSPAã§ã¯ãã»ãã·ã§ã³IDãéãããšã§ããã°ã€ã³æã«ãµãŒãã«ä¿åãããŠãŒã¶æ
å ±ãååŸããããšãã§ããããã«ããŠã¿ãŸããã
詊ãã«ãã©ãŠã¶ããªããŒãããŠã(4)ã®ãã¿ã³ãæŒããŠã¿ãŠãã ããã(3)ãå®è¡ãããšããšåãæ
å ±ãè¿ã£ãŠããããšã確èªã§ããŸãã
Google IDã§ãã°ã€ã³ããŠã¿ãã
ä»åºŠã¯ãAuth0ã䜿ããã«ãçŽæ¥Google IDã§ãã°ã€ã³ã§ããããã«ããŠã¿ãŸãã
Google ãã°ã€ã³ã®èšå®
Google IDã§OIDCãã°ã€ã³ãè¡ãããã®èšå®ã¯ãAuth0ã«æ¯ã¹ããšãå°ã倧å€ã§ãã
ãŸããGoogle Cloud Platformã§æ°ãããããžã§ã¯ããäœããŸãã
ãããŠããèªèšŒæ å ±ããéãããïŒèªèšŒæ å ±ãäœæãããããOAuthã¯ã©ã€ã¢ã³ãIDããéžæããŸãã
ãããšãå
ã«åæç»é¢ãèšå®ãããšèšãããŠããŸããŸãããèšããããšããããåæç»é¢ãèšå®ããã¯ãªãã¯ããŸãã

User Typeã¯ãäŒæ¥ãŠãŒã¶ãªã©ã§ãªãéãããå€éšãããéžæã§ããŸããã

ã¢ããªåãªã©ãå¿
èŠãªæ
å ±ãé©å®å
¥åããŸãã

ã¹ã³ãŒããéžæããããæ±ããããŸãã®ã§ãæäœé```openid``ã ãã¯æå®ããŸãã
次ã®ç»é¢ã§ããã¹ããŠãŒã¶ãç»é²ããããæ±ããããŸãããç»é²ããªããŠããã°ã€ã³ã ãã¯ã§ããããã§ãã

ä»åãçŽããŠããèªèšŒæ å ±ããéãããïŒèªèšŒæ å ±ãäœæãããããOAuthã¯ã©ã€ã¢ã³ãIDããéžæããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®çš®é¡ã¯ããŠã§ã ã¢ããªã±ãŒã·ã§ã³ããšããŸããã
æ¿èªæžã¿ã®ãªãã€ã¬ã¯ãURIã«ãhttp://localhost:3000 ã远å ããŸãã

ãäœæããæŒããšããã¯ã©ã€ã¢ã³ãIDããšãã¯ã©ã€ã¢ã³ã ã·ãŒã¯ã¬ãããã衚瀺ãããŸãã
ããããå
ã»ã©ããŠã³ããŒãããŠãããapp.jsã«ã³ããããŸãã

ããã¥ã¡ã³ããèŠãŠããGoogleã®ãOAuth Authorization URLãããOAuth Token URLãã®èšå®ã¯ã©ããªã®ãããµã³ãã«é»æä»¥å€ã§èŠã€ããããšãã§ããŸããã§ããããããããOIDC仿§ã«æºæ ããŠãOpenID ConfigurationãèŠããšããããšãªãã ãšæããŸãã(GitHubã®ãœãŒã¹ã³ãŒãã¯ãå ããGoogleã®èšå®ã«ããŠãããŸãã®ã§ãAuth0ããŸã 詊ããŠã¿ãŠããªãå Žåã¯ããã®ãŸãŸã§å€§äžå€«ã§ããïŒ
const OIDC_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth"
const OIDC_TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token"
Google IDã§ãã°ã€ã³ããŠã¿ãã
èšå®ãçµãã£ãããnode app.jsãCtrl+Cã§çµäºããŠããåèµ·åããŠãæ°ããã¿ããéã㊠ãhttp://localhost:3000ã«å床ã¢ã¯ã»ã¹ããŠèŠãŠãã ããã
(1),(2),(3)ãšé çªã«ãã¿ã³ãæŒããŠããã°ãä»åºŠã¯Googleã®IDããŒã¯ã³ã®äžèº«ãååŸã§ããŸããã
ã¡ãªã¿ã«ããæ°ããã¿ããéããŠããšãé¡ãããçç±ã¯ãåé ã§ååŸããAuth0ã®ã»ãã·ã§ã³ãæ®ã£ãŠããã°ã
ãã£ã¡åŽã®ã»ãã·ã§ã³ãã¡ãããšæå¹ã§ãAuth0ã§ååŸãããŠãŒã¶æ
å ±ãååŸããããšãã§ããŸãã
GoogleãšAuth0ã§ãisså€ãç°ãªãã®ãããããšæããŸãã
ã»ãã·ã§ã³DBã®äžèº«
ä»åäœã£ãSPAã¯ãã¢ãªã®ã§ã1ã€ã®ããŒãã«ã§ãã¹ãŠã®ããŒã¿ã管çããŠããŸããPKCEã³ãŒããšãããã°ã€ã³çµãã£ããæ¶ããŠããããã§ããã©ãã
ããšãDBã®äžãçŽæ¥èŠãŠæ°ã¥ãããã§ãããAuth0ã®subå€ã«ã¯ã|(瞊æ£) ãå«ãŸããŠãŸãããããŸã©ãããªããšæããŸãããSQLãçã§ããããããªäººã¯èŠæ³šæã§ããã
% sqlite3 oidc_db.sqlite ".schema"
CREATE TABLE session (session_id TEXT UNIQUE NOT NULL, pkce_code TEXT, subject_id TEXT, user_info TEXT, active INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')));
% sqlite3 oidc_db.sqlite "select * from session"
C2WRrorCttmBOuY9g6FXbw|jp(äžç¥)Gv|auth0|610e48bed3fd1200687bb379|{(äžç¥)"iss":"https://oidc-for-spa.jp.auth0.com/",(äžç¥)}|0|2021-08-07 18:38:58
6DvaFpPv5rVUioruwnBXxw|QU(äžç¥)6L|113688351101139242200|{"iss":"https://accounts.google.com",(äžç¥)}|1|2021-08-07 21:49:40
ææ³
OAuth / OpenID Connect ãšããæšæºã«æºæ ããŠå瀟ããµãŒãã¹ãæäŸããŠãããŠãããããã§ãæäœéã®èšå®å€æŽã§ãå瀟ã®IDaaSã䜿ã£ãŠãWebãã¢ããªã§ã®ãã°ã€ã³ãå®çŸã§ããããšãããããŸãããæšæºåãã³ã¶ã€ã







