ã¿ãªãã2022å¹´ããããéããã§ãããmacopyã§ãã
ãã®è¨äºã¯Perl Advent Calendar 2022ã®9æ¥ç®ã§ãã
追è¨: Firebase Advent Calendar 2022ã®9æ¥ç®ã空ãã¦ããã®ã§å ¥ãã¦ããã¾ããã
ä»åã¯Firebase Authenticationã使ã£ã¦ããããä½ããã¦ããªãã®ã«ãã°ã¤ã³ã§ããªããªã£ãã¨è¨ããã¦ä¸å¿ä¸ä¹±ã§ç´ãã話ããã¾ãã
Firebase Authenticationã¨ã¯
Firebase Authentication(以ä¸Firebase Auth)ã¨ã¯ãGoogleã®ã¢ããªã±ã¼ã·ã§ã³éçºãã©ãããã©ã¼ã ã§ããã¨ããã®Firebaseã®ä¸ã«ãããèªè¨¼ãµã¼ãã¹ã§ãã
ç«¶åãµã¼ãã¹ã¨ãã¦ã¯Auth0ã§ãã¤ã¾ãIDaaSã¨ãã¦ä½¿ãã¾ããå°ç¨åã®Auth0ããã¯æ©è½ã¯å°ãªãã§ãããè¤æ°ã®IdPãçµã¿åããã¦ã¦ã¼ã¶ã®èªè¨¼ç®¡çããããã¨ããç¨éã«ã¯åå使ãã¾ãã
Auth0ã«æ¯ã¹ã¦ä½¿ç¨éãå®ããã¨ãããä»ã®Firebaseã®ãµã¼ãã¹(FirestoreãHostingãConfigãªã©)ã使ããã«ãAuthã ã使ã£ã¦ããã¨ããæ¹ãããã®ã§ã¯ãªãã®ã§ãããããç§ãä»äºã§éçºãã¦ãããµã¼ãã¹ããã®ä¸ã¤ã§ãæ¬ä½ã®Webã¢ããªã±ã¼ã·ã§ã³ã¯AWSä¸ã§åãã¦ãããã®ã®ãIdPåå¥å¯¾å¿ã®å·¥æ°ãæµ®ããããã«ãIDaaSã®é¨åã ãFirebaseãç¨ãã¦ãã¾ããã
æ¤ç¥ç·¨: ããæ¥çªç¶ãªãããã°ã¤ã³ã§ããªããªã
ããæ¥ããã¤ã®ãã®ããã«ãµã¼ãã¹ã®ã¨ã´ãµã¼ãããã¦ããã¨ããã°ã¤ã³ã§ããªããã¨ãããã¤ã¼ããªã©ãããããã¨è¦åãããã¾ãããã¯ããã¯ããããäºä¾ã¨ãã¦WebViewã ã¨ã»ãã·ã§ã³ãåããåé¡ããããã°ã¤ã³ã§ãã¦ããªããã¨ãã話ãªã®ããªã¨æã£ãã®ã§ããããããªãè¤æ°äººãè¨ã£ã¦ããã®ã§ããªãã ããããããã¨ãªãã¾ãã
ã¾ãããããã人ãã¡ã®ä¸é¨ãã¹ã¯ãªã¼ã³ã·ã§ãããããã¦ããã®ã§ããè¦ãã¨ãå ¨å¡å ±éãã¦iOS Safariã§ããã
é¦ãå¾ãã¦ããã¨ããµã¼ãã¹ã®ãåãåãããã©ã¼ã ã«ãã°ã¤ã³ã§ããªãã¨ã®åãåãããæ¥ãã¨å ±åãåããã®ã§ãåãåããããã ãã£ãæ¹ã®OSã¨ãã¼ã¸ã§ã³ãèãã¦ã¿ã¾ãããããã¨ã¿ãªããiOS 16.1ã¨ãã£ãããã
ããªãã»ã©ãã
ãªããç¥ããªãããã©ãiOS 16.1ã§ãã°ã¤ã³ãã§ããªããã¨ã¯ããã£ããã¡ãªã¿ã«ããã®åé¡ãæ¤ç¥ããã®ã¯10æ29æ¥ãiOS 16.1ãReleaseãããã®ã¯10æ24æ¥ã®ããã§ãããªãªã¼ã¹ããã¦ãã䏿°ã«æ´æ°ãããããã§ã¯ãªããããããæµ¸éãã¦ããã®ã§ãç§ãã¡ã®ã¦ã¼ã¶ããã®ã¨ããã¾ã§æ¥ãã¾ã§ãããããããã£ãããã§ãã
社å ã®æ¤è¨¼æ©ç«¯æ«ãiOS 16.1ã«ããã¦ãäºè±¡ãåç¾ãã¾ãããæåã¨ãã¦ã¯ç§ãã¡ã®Webãµã¼ãã¹ããFirebase Authãçµç±ãã¦SNS飿ºå ã§ãã°ã¤ã³ãè¡ã£ãå¾ã«ãç§ãã¡ã®Webãµã¼ãã¹ã®æ»ã£ã¦ãããã°ã¤ã³ãã§ãã¦ããªãç¶æ ã§ããããããã¨æãã¾ãããçµé¨ä¸ãOSä¾åã§èµ·ããç¾è±¡ã¯ãè§£æ±ºã«æéãããããã¨ãå¤ãã§ãã
調æ»ç·¨: firebase-js-sdkã§ä¸ãã声
ãããèµ·ããç¶æ³ã¯åãã£ãããã¨ã¯ãªãèµ·ããã®ããã·ãã¥ã¬ã¼ã¿ã¼çã§æ¢ãã¤ã¤ããèªåãã¡ã®ãµã¼ãã¹ã ãã§èµ·ãã£ã¦ãããã®ããããã¨ããä»ã®ãµã¼ãã¹ãèµ·ãã£ã¦ãããã®ãã§ããããã«ãã£ã¦åé¡ã®åºæãçµãè¾¼ãã¾ãããå¾è ã§ããã°ãããã§ã«èª°ããåå ã¨è§£æ±ºæ¹æ³ãè¦ã¤ãã¦ããã®ããããã¾ããã
æ©éãfirebase auth ios 16.1ããªã©ã§ã°ã°ãã¨ãGitHubã«ããfirebase-sdk-jsãªãã¸ããªã®issueã¨ãã¦ãã§ã«ä¸ãã£ã¦ãã¾ããã
10æ22æ¥æç¹ã§Safari 16.1 betaã§äºè±¡ãèµ·ãã£ã¦ãããã¨ãããã¨ãããã§ããã¡ãªã¿ã«issueãä¸ããããæ¹ã¯iOSã§ã¯ãªãMacã®Safariã使ã£ã¦äºè±¡ãçºçããããã§ãã
firebase-js-sdkã«ã¯signInWithRedirectã¨ãã颿°ãããã¾ãã
ããã¯ãæåã¨ãã¦ã¯å¥ã®ãã¼ã¸ã«é·ç§»ããããã§OAuthãè¡ãªã£ã¦ã³ã¼ã«ããã¯ã¾ã§å¦çããä¸ã§ãå ã®Webãµã¤ãã«æ»ã£ã¦ãã¦Firebaseã®ID TokenãJSã«æ¸¡ãããããã«ãªã£ã¦ãã¾ãã
䏿¹ä¸è¨ã®issueã§å ±åããæ¹ã¯ãå¥ã®èªè¨¼æ¹æ³ã§ããsignInWithPopupã ã¨ãã°ã¤ã³ãå¯è½ã§ããã¨ãè¨ã£ã¦ãã¾ãããã¡ãã¯å¥ã®ã¦ã£ã³ãã¦ãéãã¦ãããã§OAuthãè¡ãã¾ããã¦ã£ã³ãã¦ãéããªãã¢ãã¤ã«ç°å¢ã§ã¯ã¿ãã§ä»£ç¨ããã¾ãããã¿ããããªãWebViewã§ã¯ä½¿ããã¨ãã§ããªããã¡ãªãããããã¾ããç§ãã¡ã®ã¢ããªã±ã¼ã·ã§ã³ã§ã¯ã¢ãã¤ã«ã§ã¯signInWithRedirectãPCã§ã¯signInWithPopupã使ãããã«ãã¦ãã¾ããã
解決編: signInWithCredentialãç¨ãã
ã¨ããããããããããªãããsignInWithRedirectãæªè
ã¨ãããã¨ã«ãã¦ä»ã®ææ®µãæ¢ãã¾ããå¾è¿°ãã¾ãããåå ã¯Safari 16.1ã§å¼·åãããITPã§ãã¡ã¤ã³ãã¾ããã cookieãèªããªããªã£ããã¨ãªã®ã§ããããã®æã¯ä½ãåå ãªã®ãåãã£ã¦ãã¾ããããªã®ã§å½ã¦ãã£ã½ã§ãããéçºãµã¼ãä¸ã§è²ã
試ãã¦ããã¾ãã
å
è¿°ããissueããFirebase Authã®ããã¥ã¡ã³ããè¦ã¦ããã¨ãããsignInWithRedirectãsignInWithPopup以å¤ã«signInWithCredentialãããã¨æ¸ããã¦ãã¾ãããã¡ãã¯ãOAuthãããã¯OIDCã§æã«å
¥ããã¢ã¯ã»ã¹ãã¼ã¯ã³ãªã©ã夿ãã¦Firebase Authã«æ¸¡ããã¨ã«ãã£ã¦ãèªè¨¼ãè¡ããã®ã§ãã
signInWithRedirectãsignInWithPopupã§ã¯ãã¢ã¯ã»ã¹ãã¼ã¯ã³ãID Tokenãæã«å
¥ããã®ã¯Firebase Authã®æ¹ã®è²¬åã§ããããsignInWithCredentialã使ãéãã¯ãç§ãã¡ã®ãµã¼ãã¹ã§è¡ãããã®ãã¨ã¯firebase-js-sdkã§è¡ãã¨ãããã¨ã«ãªãã¾ãã
ããã¯å ã ã®Firebase Authãå°å ¥ããçç±ã§ãã£ããç°ãªãIdPæ¯ã«å®è£ ãè¡ãã®ãçç¥ã§ããã¡ãªããããªããªããã¨ãæå³ãã¾ãããããã«ã£ã¡ããã£ã¡ãããã¾ããããã£ã¦ããï¼
ã¡ãªã¿ã«ç§ãã¡ã®ã¢ããªã±ã¼ã·ã§ã³ã§ã¯èªè¨¼é¨åã¯Perlã§æ¸ããã¦ãã¾ããIdPæ¯ã®èªè¨¼ãè¡ãªã£ã¦signInWithCredentialã«ã¢ã¯ã»ã¹ãã¼ã¯ã³ãªã©ã渡ãã®ãPerlã§å®è£ ãã¾ããããªã®ã§Perl Advent Calendarã«ãã®è¨äºãæ¸ãã¦ãã¾ãã
Googleç
åºæ¬çã«ã¯ã©ã®èªè¨¼ææ®µãAuthorization Code Flowã§ãã£ã¦ããã¾ããããã¥ã¡ã³ãã¯ä¸è¨ãOIDCã§èªè¨¼ãã¦ID Tokenãå¾ãã°ããã£ã½ãã®ã§ã以ä¸ã®ããã¥ã¡ã³ãã§ãã£ã¦ããã¾ãã
my $auth_uri = URI->new("https://accounts.google.com/o/oauth2/v2/auth"); $auth_uri->query_form( response_type => "code", client_id => $client_id, scope => "openid email", redirect_uri => $host_url . "/auth/google/callback", state => $state, nonce => $nonce, ); $c->redirect($auth_uri->as_string, 302);
ãããªæãã§èªè¨¼URLã«é£ã°ãã¦ãæ»ã£ã¦ãããã
$res = $furl->post( "https://oauth2.googleapis.com/token", [ "Content-Type" => "application/x-www-form-urlencoded" ], [ code => $code, client_id => $client_id, client_secret => $client_secret, redirect_uri => $host_url . "/auth/google/callback", grant_type => "authorization_code", ], ); my $content = decode_json($res->content); $c->session->set(google_id_token => $content->{id_token}); $c->redirect($redirect, 302);
ãããªæãã§ãã£ããã»ãã·ã§ã³ã«å ¥ãã¦ããã¦ãå¥ã®APIã¨ã³ããã¤ã³ãã§è¿ãã¦ãããããã«ãã¾ããããã ãä¸åè¿ãããããæ¶ãããã«ãã¦ããã¾ãããããªã«ãã£ã¨è¦ãã¦ããããæ å ±ã§ã¯ããã¾ããã ã³ã¼ã«ããã¯ã§ID Tokenãè¿ããã«å¥ã®APIã¨ã³ããã¤ã³ãã§è¿ãã¦ããã®ã¯ãã³ã¼ã«ããã¯URLã¯APIã§ã¯ãªããã©ã¦ã¶ä¸ã§å®éã«é·ç§»ãã¦ããã®ã§ãsignInWithCredentialãè¿ãã®ã¯é£ãããã ããã§ããmetaã¿ã°ã¨ãã«åãè¾¼ãã§ã¬ã³ããªã³ã°ã¨ããã¦ãããã°å¥ãªãã§ãããããã©ãã
Facebookç·¨
大ä½Googleã¨ä¸ç·ã§ãããFacebookã¯OIDCã§ã¯ãªãOAuth2ãªã®ã§access tokenãæ¸¡ãã¦ãããå¿ è¦ãããããã§ãã
Authorization Code Flowã§Access Tokenãå¾ã¦ããã ããªã®ã§å²æã
Twitterç·¨
ã¡ãã£ã¨æ¯è²ãéãã¾ããTwitterã®ããã¥ã¡ã³ããè¦ãã¨ãTwitterã¯OAuth 1.0aã¨æ¸ããã¦ãã¾ãã
ããã©ããããªï¼ã¨ãããã¨ã§ãNet::Twitter::Liteã®æãåãã¾ãã
my $nt = Net::Twitter::Lite::WithAPIv1_1->new( consumer_key => $client_id, consumer_secret => $client_secret, ssl => 1, ); my $callback_uri = $host_url . '/auth/twitter/callback'; my $redirect_uri = $nt->get_authorization_url(callback => $callback_uri); $c->session->set(twitter_oauth_request_token => { request_token => $nt->request_token, request_token_secret => $nt->request_token_secret, }); $c->redirect($redirect_uri);
ããã§èªè¨¼ããã¦ãè¿ã£ã¦ããã
my $nt = Net::Twitter::Lite::WithAPIv1_1->new( consumer_key => $client_id, consumer_secret => $client_secret, ssl => 1, ); $nt->request_token($request_tokens->{request_token}); $nt->request_token_secret($request_tokens->{request_token_secret}); my ($access_token, $access_token_secret) = $nt->request_access_token( verifier => $oauth_verifier, ); $c->session->set(twitter_credentials => { token => $access_token, secret => $access_token_secret, }); $c->redirect($redirect, 302);
ãããªæãã§ã¢ã¯ã»ã¹ãã¼ã¯ã³ãæã«å ¥ãã¾ãã
ã¨ã¾ããããªæãã§ããã¾ã§1æ¥ã§çµãããã¦ãæ¤è¨¼ãããã¾ãããsignInWithRedirectæä»£ã«ä½ã£ãã¢ã«ã¦ã³ãã«ç´ã¥ãSNSã¢ã«ã¦ã³ãã§signInWithCredentialã§ãã°ã¤ã³ããéã«ãã¡ããã¨åãã¢ã«ã¦ã³ãã«ãªããã¨ã確èªãã¾ããã
æ¬¡ã®æ¥ã«ããä¸åº¦ç¢ºèªãã¦ããæ¬çªåæ ãããã§ãããã§ãããã¨è¨ãã¤ã¤ãFirebase Authã使ã£ã¦ããæå³ã忏ãã¦ããã®ã§ããã£ã¨ãã解決çã¯ãªããã¨issueãç£è¦ããæ¥ã ãç¶ãã¾ãã
徿¥: å ¬å¼ã®ç·©åçãåºã
å°ãçµã£ã¦ãããissueã«è»½æ¸çã¬ã¤ããåºããã¨è²¼ããã¦ãã¾ããã
ç§ãã¡ã¯Firebase Auth以å¤ã§Firebaseãç¨ãã¦ããªãã®ã§ã軽æ¸ç1ã¯ä½¿ãããWebViewã®ã¦ã¼ã¶ããµãã¼ããããã®ã§è»½æ¸ç2ã¯ä½¿ãã¾ããã
signInWithCredentialãç¨ããæ¹æ³ã¯ã軽æ¸ç5ã«å½ããã¾ãããã ããã¡ãã¯å®è£
ã®è² æ
ã大ããã®ã§å¥ã®ãã®ã«åãæ¿ãããã¨ããã§ãã
軽æ¸ç3ã¯è¯ãããã«æãã¾ããç§ãã¡ã®ã¢ããªã¯nginxãããã®ã§ãç¹å®ã®ãã¹ã«å¯¾ãã¦Firebase Authã®ã¢ã»ããã«proxyããããã«ããã°è¯ãããã§ããåããã¡ã¤ã³ã§Firebaseã®å¦çãåãã®ã§ãcookieã®åé¡ã解決ããããã§ããã
ã¾ã¨ã
- Webã¢ããªä½ããã¦ããªãã®ã«åæã«å£ãããã¨ããã
- 仿SaaS使ããã«ä½ããã¨ãªãã¦å¤ã ããããã¦ã¼ã¶ã®ãã©ã¦ã¶ã«ãã£ã¦ãå£ããã大å¤ã§ãã
- é ã«OAuth2ã®ä»æ§ãå ¥ã£ã¦ãã¦ãµã¯ãã¨æ¬çªç´ããã®ã§è¯ãã£ãã§ãã
ãã¦ãPerl Advent Calendar 2022ã®ææ¥10æ¥ç®ã®è¨äºã¯èª°ãå ¥ã£ã¦ããªãããã§ããããããè¦ã¦ãªãã»ã©ã¨æã£ãæ¹ã¯ããã²æ¸ãã¦ã¿ã¦ã¯ãããã§ããããããããªæãã§Perlããã£ã¦ããè¨äºã§ãè¯ãããã§ãããæ¨æ¥8æ¥ç®ã®tomchaããã®è¨äºãåèã«ãã£ã¦ã¿ãã¨ããã¤ã³ã¹ãã¼ã«ãã¦ã¿ããã¨ãã§ãè¯ãããã§ãããã²åå ããå¾ ã¡ãã¦ãã¾ãã