Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHP で学ぶ OAuth 入門
Search
SAW
April 12, 2025
Programming
1.4k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PHP で学ぶ OAuth 入門
PHPカンファレンス小田原2025 の発表資料です。
SAW
April 12, 2025
More Decks by SAW
See All by SAW
Makefile 入門
azuki
0
87
Effortless API Documentation with Scribe
azuki
0
85
Laravelで手軽にAPIドキュメントを生成する ― Scribe活用術
azuki
0
56
🪝 便利な Property Hooks を 使ってみよう 🪝
azuki
0
93
決済システム超初心者が Stripe に入門している話
azuki
0
140
React Hook Form と Zod によるフォームバリデーション
azuki
0
77
PHP で form-data を POST 以外のメソッドで受け取るには?
azuki
0
90
EditorConfig を使ってみよう
azuki
1
130
Symfony でサクッと作る REST API サーバー
azuki
1
290
Other Decks in Programming
See All in Programming
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
520
Flow は今どうなっているか
mizdra
PRO
0
640
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
1.1k
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
430
What's New in Android 2026
veronikapj
0
270
PHP Application における Kubernetes 内 gRPC 通信
ganchiku
0
600
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
130
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
330
AIが無かった頃の素敵な出会いの話
codmoninc
1
470
バグを直したら useEffect が消えた
colorful12
3
640
Built Our Own Background Agent at LayerX
layerx
PRO
10
5.8k
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
4.8k
Featured
See All Featured
Accessibility Awareness
sabderemane
1
180
Balancing Empowerment & Direction
lara
6
1.2k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
370
Claude Code のすすめ
schroneko
67
230k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.4k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
250
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
Everyday Curiosity
cassininazir
0
290
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
sira's awesome portfolio website redesign presentation
elsirapls
0
330
Google's AI Overviews - The New Search
badams
0
1.1k
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Transcript
1)1ͰֶͿ0"VUIೖ 1)1ΧϯϑΝϨϯεখాݪ 4"8
$(whoami) w ࢯ໊Ճ౻फҰ ࡀ w ϋϯυϧωʔϜ4"8 w 9 چ5XJUUFS
!B[VLJ@FBUFS w ؔͷ*5ΤϯδχΞίϛϡχςΟͷ͔͠ ࣗশ w େࡕࡏॅɾѪग़ w ಘҙ8FCΞϓϦέʔγϣϯ։ൃ w -BSBWFM 7VF w ॴଐ༗ݶձࣾΞϦʔϓ 2 چ+*4ϚʔΫ ⁴ ͕ ਓͷԣإʹݟ͑ͨͷ ͚ࣗͩͰͳ͍ͣ ࠓͷ໎ݴ
ඵએ w 1)1ΧϯϑΝϨϯεؔਆށͰ։࠵ w ۚ ɾ w
։࠵ॴਆށӺલݚमηϯλʔ w ઈࢍϓϩϙʔβϧืूத w క ·Ͱ w εϙϯαʔืूத 3 ϓϩϙʔβϧืूϑΥʔϜ εϙϯαʔืूࢿྉ
͜ͷτʔΫͷ֓ཁͱඪ w ೝՄٕज़ͷͭͰ͋Δ0"VUIͷجૅΛઆ໌ w ೝূɾೝՄͷجૅ w 0"VUIͱԿ͔ w 0"VUIͷ͍Ͳ͜Ζ w
؆୯ͳ࣮ྫΛަ͑ͨ0"VUIͷೝՄॲཧͷઆ໌ w ඪ0"VUIͷجૅతͳॲཧͷྲྀΕΛ௫Ή w ʮখాݪͰΈΜͳͰֶ΅͏0"VUIʯˠʮখాݪͰجૅΛֶΜͩ0"VUIʯ 4
ຊτʔΫͷରൣғͱରऀ w ରൣғ0"VUIͷ"VUIPSJ[BUJPO$PEFͷΈ͕ର w جຊతͳॲཧϑϩʔΛத৺ʹઆ໌ w ࣮ફతͳ༰ৄࡉͳ༷ର֎ w ଞͷೝՄ༩ํࣜ *NQMJDJU
$MJFOU$SFEFOUJBMͳͲ ൣғ֎ w ରऀ0"VUIͷجૅʹڵຯͷ͋Δํ w 0"VUIʹ৮Εͨ͜ͱ͕ͳ͍ํ 5
͓͢͢Ίͷࢀߟॻ w 0"VUIపఈೖηΩϡΞͳೝՄγεςϜΛద༻͢ΔͨΊͷݪଇͱ࣮ફ w +VTUJO3JUDIFS "OUPOJP4BOTPஶɾਢాஐ೭༁ ᠳӭࣾ w 0"VUIͷجૅ͔ࣝΒؔ࿈ٕज़·Ͱ৮ΕΒΕ͍ͯΔ w
࣮ྫॆ࣮ ࣮ݴޠ+BWB4DSJQU w ͜ΕҰͰ͔ͳΓֶΔ 6
ೝূɾೝՄͱ0"VUI 7
ೝূͱೝՄ w ೝূ "VUIFOUJDBUJPO w γεςϜʹొ͞Ε͍ͯΔϢʔβʔͷຊਓΛ֬ೝ͢Δॲཧ w ྫ4/4&$αΠτͳͲͷ8FCγεςϜͷϩάΠϯ w
γεςϜʹొ͞Ε͍ͯΔϢʔβʔใͱ߹க͢Δ͜ͱͰγεςϜ͕ར༻Ͱ͖Δ w ೝՄ "VUIPSJ[BUJPO w γεςϜͷػೳϦιʔεͷΞΫηεͷՄ൱Λ੍ޚ͢Δॲཧ w ྫ6/*9ͷϑΝΠϧγεςϜͷύʔϛογϣϯ w ϑΝΠϧͷૢ࡞͕ͦͷϢʔβʔʹରͯ͠ڐՄ͞Ε͍ͯΔ߹ʹͷΈૢ࡞͕Մೳ 8
0"VUIͱ w 0"VUI8FCΞϓϦέʔγϣϯʹ͓͚ΔೝՄͷͨΊͷϓϩτίϧ w SEύʔςΟͷγεςϜ͔Β8FCαʔϏεʹΞΫηε͢Δ͜ͱΛೝՄ w ΞΫηετʔΫϯΛར༻ͯ͠8FCαʔϏεʹΞΫηε w ೝূʹؔ͢ΔϓϩτίϧͰͳ͍͜ͱʹҙ w
ڐՄ͞Εͨݖݶͷൣғ είʔϓ ͰͷΈΞΫηε͕Մೳ w ݖݶͷൣғ8FCαʔϏεͷར༻ऀ͕ڐՄͨ͠ൣғ 9
0"VUIͷར༻ྫ w ESBXJP͔Β(PPHMF%SJWFʹΞΫηε w ESBXJP8FC্Ͱ࡞ਤͰ͖ΔαʔϏε w (PPHMF%SJWF(PPHMFͷΫϥυετϨʔδαʔϏε w ESBXJP͕(PPHMF%SJWFʹٻΊΔΞΫηεݖͷྫ w
ετϨʔδͷϑΝΠϧͷಡΈࠐΈ w ετϨʔδͷϑΝΠϧͷอଘ 10 ESBXJP͔Β(PPHMF%SJWFͷ ΞΫηεͷೝՄΛཁٻ (PPHMF%SJWFͰΞΫηεݖͷೝՄΛ֬ೝ
ͳͥ0"VUI͔ w 8FCαʔϏεͷೝূใΛSEύʔςΟͷγεςϜͱڞ༗͠ͳ͍ w 8FCαʔϏεଆͷೝূใΛมߋͯ͠ӨڹΛड͚ͳ͍ w ͦͦηΩϡϦςΟతʹೝূใΛ֎෦γεςϜͱڞ༗ͨ͘͠ͳ͍ w SEύʔςΟͷγεςϜ͕ཁٻ͢ΔݖݶΛ֬ೝͰ͖Δ w
ཁٻ͞ΕΔݖݶͷ༰͕Ϣʔβʔʹࣔ͞ΕΔ w ϢʔβʔͷڐՄͳ͠ʹݖݶ͕༩͞ΕΔ͜ͱ͕ͳ͍ 11 ESBXJP͕ཁٻ͢Δ(PPHMF%SJWFͷݖݶͷ༰Λ Ϣʔβʔʹ֬ೝ͢Δྫ
0"VUIͷॲཧϑϩʔ 12
0"VUIʹ͓͚Δొਓ w ΫϥΠΞϯτ $MJFOU w อޢରϦιʔεʹΞΫηε͢ΔSEύʔςΟͷιϑτΣΞ w อޢରϦιʔε 1SPUFDUFE3FTPVSDF
w Ϧιʔεॴ༗ऀ͕ΞΫηεݖΛ࣋ͭػೳσʔλͳͲͷϦιʔε w Ϧιʔεॴ༗ऀ 3FTPVSDF0XOFS w อޢରϦιʔεͷΞΫηεݖΛͭϢʔβʔ w ೝՄαʔόʔ "VUIPSJ[BUJPO4FSWFS w Ϧιʔεॴ༗ऀ͕ΫϥΠΞϯτΛೝՄ͢ΔΈΛఏڙ͢ΔγεςϜ 13
ొਓͷ۩ମྫ w ΫϥΠΞϯτESBXJP w อޢରϦιʔε(PPHMF%SJWF"1* w Ϧιʔεॴ༗ऀϒϥβΛૢ࡞͍ͯ͠ΔϢʔβʔ w ೝՄαʔόʔ(PPHMFͷ0"VUIೝՄαʔόʔ 14
0"VUIͷॲཧϑϩʔ Ϧιʔεॴ༗ऀ͕ΫϥΠΞϯτΛೝՄ w ཁٻ͞ΕΔݖݶͷ༰ΛϦιʔεॴ༗ऀʹఏࣔͯ͠ೝՄ͢Δ͔֬ೝ ೝՄαʔόʔೝՄίʔυΛੜ ΫϥΠΞϯτೝՄίʔυ͔ΒΞΫηετʔΫϯΛऔಘ
ΫϥΠΞϯτΞΫηετʔΫϯΛར༻ͯ͠อޢରϦιʔεʹΞΫηε 15
0"VUIͷॲཧϑϩʔ 16 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΫϥΠΞϯτΛೝՄ
0"VUIͷॲཧϑϩʔ 17 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄαʔόʔʹϦμΠϨΫτ ೝՄαʔόʔʹϦμΠϨΫτ
0"VUIͷॲཧϑϩʔ 18 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηεݖͷೝՄΛ֬ೝ
0"VUIͷॲཧϑϩʔ 19 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηεݖΛೝՄ
0"VUIͷॲཧϑϩʔ 20 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄίʔυΛΫϥΠΞϯτʹ ϦμΠϨΫτ ೝՄίʔυΛ ΫϥΠΞϯτʹ
ϦμΠϨΫτ
0"VUIͷॲཧϑϩʔ 21 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄίʔυΛ ૹ৴
0"VUIͷॲཧϑϩʔ 22 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηετʔΫϯΛ ൃߦ
0"VUIͷॲཧϑϩʔ 23 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ΞΫηετʔΫϯΛਵͯ͠ อޢରϦιʔεʹΞΫηε
0"VUIͷॲཧϑϩʔ 24 ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ อޢରϦιʔε ೝՄ͞ΕͨείʔϓͰ ϦιʔεΛฦ٫
ೝՄίʔυͱΞΫηετʔΫϯ w ೝՄίʔυΞΫηετʔΫϯΛಘΔͨΊͷҰ࣌తͳίʔυ w Ϧιʔεॴ༗ऀʹΑΔΫϥΠΞϯτͷೝՄͷ݁ՌΛࣔ͢ίʔυ w codeͱ͍͏ΫΤϦύϥϝʔλʔΛ༩ͯ͠ΫϥΠΞϯτʹϦμΠϨΫτ w ΞΫηετʔΫϯอޢରϦιʔεͷΞΫηεͰར༻͢ΔτʔΫϯ w
อޢରϦιʔεΞΫηετʔΫϯΛड͚औͬͯݖݶΛ֬ೝͯ͠ϦιʔεΛฦ͢ w อޢରϦιʔεΫϥΠΞϯτ͔Β#FBSFSτʔΫϯͰड͚औΔ 25
είʔϓ w อޢରϦιʔεͷΞΫηεݖΛࣔ͢จࣈྻ w ෳͷείʔϓۭനจࣈ۠ΓʹΑͬͯදݱ͞ΕΔ w ΫϥΠΞϯτ͕ΞΫηεͰ͖ΔൣғείʔϓͰࣔ͞ΕͨൣғͷΈ w Ϧιʔεॴ༗ऀ͕ೝՄ͍ͯ͠ͳ͍είʔϓͷϦιʔεʹΞΫηεෆՄ 26
֤ॲཧϑϩʔͷ࣮ྫ 27
࣮ྫʹ͍ͭͯ w -BSBWFMͷίʔυͷҰ෦Λར༻ͯ͠આ໌ w 8FCαʔόʔͷػೳͳͲ0"VUIͷຊ࣭Ͱͳ͍෦ͷ࣮Λ؆ܿԽ w ෦ॲཧΛӅณ͠ͳ͍ͨΊʹ0"VUIͷϥΠϒϥϦར༻͠ͳ͍ w ࣮ફతͳΞϓϦέʔγϣϯ։ൃͰ0"VUIͷϥΠϒϥϦΛ͏ํ͕ྑ͍ w
0"VUIͷ࣮ʹ͓͍ͯݴޠϑϨʔϜϫʔΫෆ w ཧղͷ͢͠͞Λ༏ઌ w όϦσʔγϣϯͳͲͷ࣮ફతͳ༰লུ 28
࣮ྫͷ֤ߏཁૉͷΞΫηε w Ϧιʔεॴ༗ऀਓؒ ϒϥβ w ΫϥΠΞϯτlocalhost:8000 w ೝՄαʔόʔlocalhost:8001 w
อޢରϦιʔεlocalhost:8002 29
ΫϥΠΞϯτͷೝՄཁٻ w Ϧιʔεॴ༗ऀΛೝՄαʔόʔʹϦμΠϨΫτ w ϦμΠϨΫτ࣌ʹೝՄରͷΫϥΠΞϯτͷใΛΫΤϦύϥϝʔλʹ༩ 30 $query = http_build_query([ 'response_type'
=> 'code', 'client_id' => env('CLIENT_ID'), 'redirect_uri' => 'http://localhost:8000/callback', 'scope' => 'file.read file.write', ]); $authEndpoint = Uri::new('http://localhost:8001/authorize') ->withQuery($query); return redirect()->away($authEndpoint); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ ೝՄαʔόʔʹ ϦμΠϨΫτ localhost:8000 localhost:8001 ༩ํࣜBVUIPSJ[BUJPODPEF ΫϥΠΞϯτ͕ཁٻ͢Δείʔϓ
ΫϥΠΞϯτͷೝՄͷ֬ೝ w ΫϥΠΞϯτΛೝՄ͢Δ͔Ϧιʔεॴ༗ऀʹ֬ೝ w είʔϓۭനจࣈ۠ΓͰΫΤϦύϥϝʔλͰ͞ΕΔ 31 $clientId = $request->query('client_id'); $client
= Client::find($clientId); // 要求されているスコープを取得 $scope = str($request->query('scope')) ->explode(' ')->filter(); return view('authorize', [ 'client' => $client, 'scope' => $scope, ]); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτͷ ೝՄΛ֬ೝ localhost:8001
ΫϥΠΞϯτͷೝՄ w ೝՄίʔυΛൃߦͯ͠ΫϥΠΞϯτͷίʔϧόοΫ63-ʹϦμΠϨΫτ w ೝՄίʔυͱϦιʔεॴ༗ऀ͕ڐՄͨ͠είʔϓΛΫΤϦύϥϝʔλͱͯ͠༩ 32 $scope = $request->input('scope'); $authzCode
= Str::random(); $codes[$authzCode] = ['scope' => $scope]; Cache::put('codes', $codes); $callbackUrl = Uri::new($redirectUrl) ->withQuery([ 'scope' => $scope, 'code' => $authzCode, ]); return redirect()->away($callbackUrl); ೝՄαʔόʔ Ϧιʔεॴ༗ऀ ΫϥΠΞϯτ ΫϥΠΞϯτʹ ϦμΠϨΫτ localhost:8000 localhost:8001 ೝՄίʔυΛ༩
τʔΫϯͷऔಘ w ΫϥΠΞϯτೝՄαʔόʔʹೝՄίʔυΛૹ৴ w ΫϥΠΞϯτ#BTJDೝূͰࣝผ w ೝՄαʔόʔΫϥΠΞϯτʹΞΫηετʔΫϯΛൃߦ 33 ೝՄαʔόʔ ΫϥΠΞϯτ
ೝূใͱೝՄίʔυΛ ૹ৴ localhost:8000 localhost:8001 $clientId = $request->getUser(); $clientSecret = $request->getPassword(); $codes = Cache::get('codes'); $code = $codes[$request->input('code')]; // クライアントの情報と認可コードを検証 $token = Str::random(); AccessToken::create(['token' => $token]); return response()->json([ 'access_token' => $token, 'token_type' => 'Bearer', 'scope' => $code['scope'], ]); ΞΫηετʔΫϯΛૹ৴ #BTJDೝূͰΫϥΠΞϯτΛࣝผ
อޢରϦιʔεͷΞΫηε w ΫϥΠΞϯτอޢରϦιʔεʹΞΫηετʔΫϯΛར༻ͯ͠ΞΫηε w ΞΫηετʔΫϯ#FBSFSτʔΫϯͰ͞ΕΔ w อޢରϦιʔεϦιʔεΛΫϥΠΞϯτʹฦ٫ w ೝՄ͞Εͨείʔϓ֎ͷΞΫηεڐՄ͠ͳ͍ 34
ΫϥΠΞϯτ ΞΫηετʔΫϯΛ༩ͯ͠ ϦιʔεʹΞΫηε localhost:8000 localhost:8002 Ϧιʔεͷ༰Λฦ٫ อޢରϦιʔε $token = $request->bearerToken(); $accessToken = AccessToken::whereFirst('token', $token); if ($accessToken?->scope->contains('file.read')) { $content = Storage::json('data.json'); return response()->json($content); } else { return response()->json(null, 403); } #FBSFSτʔΫϯ͔Β ΞΫηετʔΫϯΛऔಘ ΞΫηετʔΫϯʹཁٻ͞ΕΔ είʔϓ͕ଘࡏ͢Δ͔νΣοΫ
མึर͍ w ϦϑϨογϡτʔΫϯΞΫηετʔΫϯΛ࠶ൃߦ͢ΔͨΊͷίʔυ w ༗ޮظݶ͕Εͨ߹ͳͲʹϦιʔεॴ༗ऀʹೝՄΛٻΊΔ͜ͱͳ͘࠶ൃߦ w TUBUF$43'Λ͙ͨΊͷύϥϝʔλʔ w ೝՄίʔυͷૹ৴ݩ͕Ϧιʔεॴ༗ऀ͕ೝՄͨ͠ΫϥΠΞϯτͱಉҰ͔֬ೝ 35
্༷ඞਢͰͳ͍͕ɺηΩϡϦςΟϗʔϧʹͳΔͨΊ ࣄ্࣮ඞਢͷύϥϝʔλͱߟ͑ͨํ͕ྑ͍ ه
·ͱΊ w 0"VUIͷجૅʹ͍ͭͯઆ໌ w ೝূɾೝՄʹ͍ͭͯઆ໌ w 0"VUIͷ֓ཁͱ࣮ྫΛઆ໌ w 0"VUIͷೝՄॲཧϑϩʔʹ͍ͭͯઆ໌ w
֤ཁૉͷॲཧ༰Λ؆୯ͳ࣮ྫΛ༻͍ͯઆ໌ 36
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠