-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathadv_authentication.html
More file actions
695 lines (655 loc) · 47.6 KB
/
adv_authentication.html
File metadata and controls
695 lines (655 loc) · 47.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
<!doctype html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Advanced Authentication — Ruby on Rails Guides</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" data-turbo-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight.css" data-turbo-track="reload">
<link rel="icon" href="images/backend-development.svg" sizes="any">
<script src="javascripts/@hotwired--turbo.js" data-turbo-track="reload"></script>
<script src="javascripts/clipboard.js" data-turbo-track="reload"></script>
<script src="javascripts/guides.js" data-turbo-track="reload"></script>
<meta property="og:title" content="Advanced Authentication — Ruby on Rails Guides" />
<meta name="description" content="Advanced AuthenticationThis guide is about Authentication for Web and Mobile Apps.After reading this guide you will have an overview of scenarios and authentication methods be able to use several authentication methods in next.js be able to use several authentication methods in rails" />
<meta property="og:description" content="Advanced AuthenticationThis guide is about Authentication for Web and Mobile Apps.After reading this guide you will have an overview of scenarios and authentication methods be able to use several authentication methods in next.js be able to use several authentication methods in rails" />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Textbook Backend Developemnt" />
<meta property="og:image" content="images/backend-development.svg" />
<meta property="og:type" content="website" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Heebo:wght@100..900&family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet">
<meta name="theme-color" content="#2e56e9">
</head>
<body class="guide">
<header id="page_header">
<div class="wrapper clearfix">
<nav id="feature_nav">
<div class="header-logo">
<a href="/">Backend Development</a>
</div>
<ul class="nav">
<li><a class="nav-item" id="home_nav" href="/">Home</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">Index</a>
<div id="guides" class="clearfix" style="display: none;">
<hr />
<dl class="guides-section-container">
<div class="guides-section">
<dt>Ruby on Rails</dt>
<dd><a href="ruby_commandline.html">Ruby Commandline</a></dd>
<dd><a href="rails_database_and_model.html">Models and ActiveRecord</a></dd>
<dd><a href="rails_db.html">Database and Migrations</a></dd>
<dd><a href="rails_associations_and_validations.html">Associations and Validations</a></dd>
<dd><a href="rails_view_and_controller.html">Routing, View and Controller</a></dd>
<dd><a href="rails_authentication.html">Simple Authentication</a></dd>
<dd><a href="assets_and_import_map.html">The Asset Pipeline and Importmaps</a></dd>
<dd><a href="testing.html">Getting started with Testing</a></dd>
<dd><a href="refactoring_rails.html">Refactoring Rails</a></dd>
<dd><a href="deploy-to-paas.html">Deploy to PAAS</a></dd>
<dd><a href="rails_gems.html">Ruby Gems for your Rails Project</a></dd>
<dd><a href="deploying_rails.html">Deploying Rails</a></dd>
</div>
<div class="guides-section">
<dt>Ruby on Rails - Advanced Topics</dt>
<dd><a href="deploy-to-paas.html">Deploy to PAAS</a></dd>
<dd><a href="rest-api.html">REST API</a></dd>
<dd><a href="graphql-api.html">GraphQL API</a></dd>
<dd><a href="rails_websockets.html">Websocket in Rails</a></dd>
<dd><a href="jobs_and_tasks.html">Jobs and Tasks in Rails</a></dd>
<dd><a href="rails_security.html">Rails Security</a></dd>
</div>
<div class="guides-section">
<dt>Overarching Concerns</dt>
<dd><a href="issue.html">Issue Lifecycle</a></dd>
<dd><a href="security.html">Security</a></dd>
<dd><a href="adv_authentication.html">Advanced Authentication</a></dd>
<dd><a href="caching.html">Caching</a></dd>
<dd><a href="advanced_testing.html">Advanced Testing</a></dd>
<dd><a href="internationalization.html">Internationalization (I18n)</a></dd>
<dd><a href="git_rebasing.html">Git Rebasing</a></dd>
</div>
<div class="guides-section">
<dt>Nodes.js</dt>
<dd><a href="node_vs_rails.html">Node vs. Rails</a></dd>
<dd><a href="node_basics.html">Node Basics</a></dd>
<dd><a href="node_websockets.html">Node Websockets</a></dd>
<dd><a href="node_express.html">Node Web App</a></dd>
<dd><a href="node_cluster.html">Scaling Node</a></dd>
</div>
<div class="guides-section">
<dt>Next.js</dt>
<dd><a href="nextjs.html">Next.js</a></dd>
</div>
</dl>
</div>
</li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">Index</option>
<optgroup label="Ruby on Rails">
<option value="ruby_commandline.html">Ruby Commandline</option>
<option value="rails_database_and_model.html">Models and ActiveRecord</option>
<option value="rails_db.html">Database and Migrations</option>
<option value="rails_associations_and_validations.html">Associations and Validations</option>
<option value="rails_view_and_controller.html">Routing, View and Controller</option>
<option value="rails_authentication.html">Simple Authentication</option>
<option value="assets_and_import_map.html">The Asset Pipeline and Importmaps</option>
<option value="testing.html">Getting started with Testing</option>
<option value="refactoring_rails.html">Refactoring Rails</option>
<option value="deploy-to-paas.html">Deploy to PAAS</option>
<option value="rails_gems.html">Ruby Gems for your Rails Project</option>
<option value="deploying_rails.html">Deploying Rails</option>
</optgroup>
<optgroup label="Ruby on Rails - Advanced Topics">
<option value="deploy-to-paas.html">Deploy to PAAS</option>
<option value="rest-api.html">REST API</option>
<option value="graphql-api.html">GraphQL API</option>
<option value="rails_websockets.html">Websocket in Rails</option>
<option value="jobs_and_tasks.html">Jobs and Tasks in Rails</option>
<option value="rails_security.html">Rails Security</option>
</optgroup>
<optgroup label="Overarching Concerns">
<option value="issue.html">Issue Lifecycle</option>
<option value="security.html">Security</option>
<option value="adv_authentication.html">Advanced Authentication</option>
<option value="caching.html">Caching</option>
<option value="advanced_testing.html">Advanced Testing</option>
<option value="internationalization.html">Internationalization (I18n)</option>
<option value="git_rebasing.html">Git Rebasing</option>
</optgroup>
<optgroup label="Nodes.js">
<option value="node_vs_rails.html">Node vs. Rails</option>
<option value="node_basics.html">Node Basics</option>
<option value="node_websockets.html">Node Websockets</option>
<option value="node_express.html">Node Web App</option>
<option value="node_cluster.html">Scaling Node</option>
</optgroup>
<optgroup label="Next.js">
<option value="nextjs.html">Next.js</option>
</optgroup>
</select>
</li>
</ul>
</nav>
</div>
</header>
<hr class="hide" />
<section id="feature">
<div class="wrapper">
<h1>Advanced Authentication</h1><p>This guide is about Authentication for Web and Mobile
Apps.</p><p>After reading this guide you will</p>
<ul>
<li>have an overview of scenarios and authentication methods</li>
<li>be able to use several authentication methods in next.js</li>
<li>be able to use several authentication methods in rails</li>
</ul>
<nav id="subCol">
<h3 class="chapter">
<picture>
<!-- Using the `source` HTML tag to set the dark theme image -->
<source
srcset="images/icon_book-close-bookmark-1-wht.svg"
media="(prefers-color-scheme: dark)"
/>
<img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" />
</picture>
Chapters
</h3>
<ol class="chapters">
<li><a href="#concepts">Concepts</a>
<ul>
<li><a href="#authentication-and-authorisation-scencarios">Authentication and Authorisation Scencarios</a></li>
<li><a href="#two-factor-authentication">Two Factor Authentication</a></li>
<li><a href="#different-types-of-programs">Different types of programs</a></li>
<li><a href="#command-line-authentication-flow">Command Line Authentication Flow:</a></li>
</ul></li>
<li><a href="#how-to-add-state-to-http">How to add state to HTTP</a>
<ul>
<li><a href="#http-basic-authentication">HTTP Basic Authentication</a></li>
<li><a href="#http-cookies">HTTP Cookies</a></li>
<li><a href="#bearer-token">Bearer Token</a></li>
</ul></li>
<li><a href="#web-authentication-webauthn">Web Authentication "WebAuthn"</a>
<ul>
<li><a href="#passkey">Passkey</a></li>
</ul></li>
<li><a href="#openid-oauth">OpenID + OAuth</a></li>
<li><a href="#jwt">JWT</a>
<ul>
<li><a href="#encoding-a-token">Encoding a Token</a></li>
</ul></li>
<li><a href="#rails">Rails</a>
<ul>
<li><a href="#oauth">OAuth</a></li>
<li><a href="#webauth">WebAuth</a></li>
<li><a href="#json-web-tokens-jwt">JSON Web Tokens (JWT)</a></li>
</ul></li>
<li><a href="#next-js">next.js</a>
<ul>
<li><a href="#oauth2">OAuth2</a></li>
<li><a href="#configuring-the-authentication-provider">configuring the authentication provider</a></li>
<li><a href="#configuring-the-callback">configuring the callback</a></li>
<li><a href="#link-to-sign-in-and-sign-out">link to sign in and sign out</a></li>
<li><a href="#in-server-components">in server components</a></li>
<li><a href="#in-client-components">in client components</a></li>
</ul></li>
<li><a href="#further-reading">Further Reading</a></li>
</ol>
</nav>
<hr>
</div>
</section>
<main id="container">
<div class="wrapper">
<div id="mainCol">
<div class='slide'>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-0' href='slides_adv_authentication.html#/0'>◻</a></p>
<h2 id="concepts"><a class="anchorlink" href="#concepts"><span>1</span> Concepts</a></h2></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-1' href='slides_adv_authentication.html#/1'>◻</a></p>
<h3 id="authentication-and-authorisation-scencarios"><a class="anchorlink" href="#authentication-and-authorisation-scencarios"><span>1.1</span> Authentication and Authorisation Scencarios</a></h3><p>Some questions to ask yourself:</p>
<ul>
<li>Do I only need authentication (is this the user?)</li>
<li>Do I need authorisation to access resources on other servers in the users name?</li>
<li>Is one factor enough? Do I want to support 2 factor authentication?</li>
<li>Who does the authentication? My own app or another "authentication provider"?</li>
<li>Which programs need to authenticate? Browsers? Native apps? Command line programs?</li>
<li>Are users expecting a "single sign on"?</li>
</ul>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-2' href='slides_adv_authentication.html#/2'>◻</a></p>
<h3 id="two-factor-authentication"><a class="anchorlink" href="#two-factor-authentication"><span>1.2</span> Two Factor Authentication</a></h3><p>any combination of:</p>
<ul>
<li> Something you know - a password or a pin</li>
<li> Something you have - mobile phone or a security token like a <a href="https://www.yubico.com/products/#yubikey-5ci">YubiKey</a></li>
<li> Something you are - fingerprint, retina scan, FaceID</li>
<li> Something you do - typing speed, locational information etc.</li>
</ul>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-3' href='slides_adv_authentication.html#/3'>◻</a></p>
<h3 id="different-types-of-programs"><a class="anchorlink" href="#different-types-of-programs"><span>1.3</span> Different types of programs</a></h3><p>When creating command line programs, web apps, native apps we
have different possibilities.</p><p>You already know how to use HTTP Cookies for authentication
in a web app. Command line programs and native app do not use cookies
automatically as browser do.</p><p>To illustrate this let's look at a command line program.</p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-4' href='slides_adv_authentication.html#/4'>◻</a></p>
<h3 id="command-line-authentication-flow"><a class="anchorlink" href="#command-line-authentication-flow"><span>1.4</span> Command Line Authentication Flow:</a></h3><p>Here an example of an authentication flow for the
office365 command line tool:</p>
<ol>
<li>start the process on the command line</li>
</ol>
<p><img src="images/office-cli-1.png" alt="Command Line"></p><p>the program opens a browser at a special Microsoft login page
and asks you to type in a short string there.</p><p><img src="images/cli-login-3.png" alt="Command Line"></p><p>go throug the usual steps of login</p><p><img src="images/cli-login-4.png" alt="Command Line"></p><p>final screen in the browser shows success</p><p><img src="images/cli-login-5.png" alt="Command Line"></p><p>back in the command line program you are now authorized.</p><p><img src="images/office-cli.png" alt="Command Line"></p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-5' href='slides_adv_authentication.html#/5'>◻</a></p>
<h2 id="how-to-add-state-to-http"><a class="anchorlink" href="#how-to-add-state-to-http"><span>2</span> How to add state to HTTP</a></h2><p>When thinking about Authentication and Web Applications we
first have to overcome the stateless nature of HTTP.
There are several ways to do this:</p>
<ol>
<li> <strong>HTTP Basic Authentication</strong></li>
<li> <strong>HTTP Cookies</strong></li>
<li> <strong>Bearer-Token</strong></li>
</ol>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-6' href='slides_adv_authentication.html#/6'>◻</a></p>
<h3 id="http-basic-authentication"><a class="anchorlink" href="#http-basic-authentication"><span>2.1</span> HTTP Basic Authentication</a></h3><p>This is the oldest method. It still works in all the browser, but is not used much
any more because the UI is very restrictive.</p><p><img src="images/chrome-basic.png" alt=""></p><p>It is specified in <a href="https://tools.ietf.org/html/rfc1945#section-11">RFC 1945, section 11</a>.</p>
<ol>
<li>The Browser requests access to a resource;</li>
<li>The server sends a <code>WWW-Authenticate: Basic ...</code> header in the response, but not the resource;</li>
<li>The browser asks the user for username and password through a popup window</li>
<li>The browser sends the (hashed) username and password to the server with all subsequent request using the HTTP Headers <code>Authorization: Basic ...</code></li>
</ol>
<p>This can be configured in the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#restricting_access_with_apache_and_basic_authentication">web server</a>.</p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-7' href='slides_adv_authentication.html#/7'>◻</a></p>
<h3 id="http-cookies"><a class="anchorlink" href="#http-cookies"><span>2.2</span> HTTP Cookies</a></h3><p>HTTP Cookies are defined in <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>.</p>
<ol>
<li>The server sets the cookie (using the Header 'Set-Cookie'),</li>
<li>the client includes the cookie automatically in every subsequent request to the server (using the HTTP Header <code>Cookie</code>).</li>
</ol>
<p>Cookies are often integrated into backend frameworks as a method
to identify sessions.</p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-8' href='slides_adv_authentication.html#/8'>◻</a></p>
<h3 id="bearer-token"><a class="anchorlink" href="#bearer-token"><span>2.3</span> Bearer Token</a></h3><p>This method uses the same HTTP Header <code>Authorization</code> as HTTP Basic authentication,
<a href="https://tools.ietf.org/html/rfc1945#section-11">rfc 1945, section 11</a>.</p><p>The client sends the token with the <code>Authorization: Bearer ...</code> HTTP header.</p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-9' href='slides_adv_authentication.html#/9'>◻</a></p>
<h2 id="web-authentication-webauthn"><a class="anchorlink" href="#web-authentication-webauthn"><span>3</span> Web Authentication "WebAuthn"</a></h2><p>Web Authentication, or short "WebAuthn" is a W3C standard
that has been implemented <a href="https://caniuse.com/?search=webauthn">in all Browsers since 2020</a>.</p><p>You a User you have to own an authenticator: for example a <a href="https://www.yubico.com/">YubiKey</a>, USB Token,
or your <a href="https://www.makeuseof.com/set-up-passkey-google-account-android/">smartphone</a>.
This Authenticator
is a powerful "second factor": it can do cryptographic computation and it can
store data.</p><p><img src="images/yubikey-5.png" alt=""></p><p>This diagram <a href="https://auth0.com/blog/introduction-to-web-authentication/">from auth0</a> shows the players
in this form auf authentication:</p><p><img src="images/web-authn-entities.png" alt=""></p><p>The server you want to log into is called the "relying party".</p><p>During <strong>Registration</strong> the relying party supplies data called "challenge". The JavaScript
in the users browser calls <code>navigator.credentials.create()</code> with this challenge. This makes
the browser call the authenticator device with the challenge data. The device might ask the user
for some form of consent, for example given through a fingerprint or a touch sensor.
The result is a public/private key pair.</p><p>During <strong>Authentication</strong> (or "attestation") the same challenge from the relying party
is given to the authenticator.</p><p>See also</p>
<ul>
<li><a href="https://webauthn.guide/">Guide</a></li>
<li><a href="https://webauthn.io/">Demo</a></li>
<li><a href="https://github.com/herrjemand/awesome-webauthn">awesome-webauthn collection on Github</a></li>
</ul>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-10' href='slides_adv_authentication.html#/10'>◻</a></p>
<h3 id="passkey"><a class="anchorlink" href="#passkey"><span>3.1</span> Passkey</a></h3></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-11' href='slides_adv_authentication.html#/11'>◻</a></p>
<h2 id="openid-oauth"><a class="anchorlink" href="#openid-oauth"><span>4</span> OpenID + OAuth</a></h2><p>OpenID 2.0 is an open standard for Authentication.</p><p>OAuth is and open standard for API Access delegation originally published in 2010.
The current version is <a href="https://oauth.net/2/">OAuth 2.0</a>, published as RFC 6749 and RFC 6750 in 2012.</p><p>Both follow the same flow:</p>
<ol>
<li> The user requests a resource or site login from the application.</li>
<li> The site sees that the user is not authenticated. It formulates a request for the identity provider, encodes it, and sends it to the user as part of a redirect URL.</li>
<li> The user's browser makes a request to the redirect URL for the identity provider, including the application's request</li>
<li> If necessary, the identity provider authenticates the user (perhaps by asking them for their username and password)</li>
<li> Once the identity provider is satisfied that the user is sufficiently authenticated, it processes the application's request, formulates a response, and sends that back to the user along with a redirect URL back to the application.</li>
<li> The user's browser requests the redirect URL that goes back to the application, including the identity provider's response</li>
<li> The application decodes the identity provider's response, and carries on accordingly.</li>
<li> (OAuth only) The response includes an access token which the application can use to gain direct access to the identity provider's services on the user's behalf.</li>
</ol>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-12' href='slides_adv_authentication.html#/12'>◻</a></p>
<h2 id="jwt"><a class="anchorlink" href="#jwt"><span>5</span> JWT</a></h2><p><strong>JSON-Web-Token</strong> are a way to encode and sign JSON-Data. You
can use many transmission methods to send them:</p>
<ul>
<li>HTTP-Headers <code>Authorization: Bearer ...</code> or <code>Cookie</code></li>
<li>Parameter in an URL</li>
<li><p>POST data</p></li>
<li><p><a href="https://jwt.io/">jwt.io</a> / <a href="https://tools.ietf.org/html/rfc7519">rfc 7519</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=P2CPd9ynFLg">Video on JWT by ByteByteGo</a></p></li>
</ul>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-13' href='slides_adv_authentication.html#/13'>◻</a></p>
<h3 id="encoding-a-token"><a class="anchorlink" href="#encoding-a-token"><span>5.1</span> Encoding a Token</a></h3><p>A JWT consists of three parts: header, payload and signature.
All three are encoded and concatenated with a dot. The result
looks like this (if you color-code it):</p><p><img src="images/encoded-jwt3.png" alt=""></p><p>The encoding consists of two steps:</p>
<ul>
<li>with <a href="https://en.wikipedia.org/wiki/Base64#Examples">Base64</a>
endcoding the input string is converted to a new, longer string of only 64 characters
that are considered "save" for transfer via (ASCII only) e-mail. Three bytes of the original are encoded into 4 bytes in
the resulting string. Base64 encoded strings may contain plus signs and are
padded with equal signs at the end.</li>
<li>As a second step the plus signs are replaced by minus signs and
the padding is dropped, resulting in a string that can be used in a URL without problems:</li>
</ul>
<div class="interstitial code">
<pre><code class="highlight js"><span class="p">{</span> <span class="dl">"</span><span class="s2">msg_en</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Hello</span><span class="dl">"</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">msg_jp</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">こんにちは</span><span class="dl">"</span>
<span class="dl">"</span><span class="s2">msg_de</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Guten Tag</span><span class="dl">"</span> <span class="p">}</span>
<span class="nx">eyAibXNnX2VuIjogIkhlbGxvIiwKICAibXNnX2pwIjogIuOBk</span><span class="o">+</span><span class="nx">OCk</span><span class="o">+</span><span class="nx">OBq</span><span class="o">+</span><span class="nx">OBoeOBryIKICAibXNnX2RlIjogIkd1dGVuIFRhZyIgfQ</span><span class="o">==</span>
<span class="nx">eyAibXNnX2VuIjogIkhlbGxvIiwKICAibXNnX2pwIjogIuOBk</span><span class="o">-</span><span class="nx">OCk</span><span class="o">-</span><span class="nx">OBq</span><span class="o">-</span><span class="nx">OBoeOBryIKICAibXNnX2RlIjogIkd1dGVuIFRhZyIgfQ</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="{ "msg_en": "Hello",
"msg_jp": "こんにちは"
"msg_de": "Guten Tag" }
eyAibXNnX2VuIjogIkhlbGxvIiwKICAibXNnX2pwIjogIuOBk+OCk+OBq+OBoeOBryIKICAibXNnX2RlIjogIkd1dGVuIFRhZyIgfQ==
eyAibXNnX2VuIjogIkhlbGxvIiwKICAibXNnX2pwIjogIuOBk-OCk-OBq-OBoeOBryIKICAibXNnX2RlIjogIkd1dGVuIFRhZyIgfQ
">Copy</button>
</div>
<p>You can use the <a href="https://jwt.io/#debugger-io">JWT Debugger</a> to decode this.</p><p><img src="images/jwt-debugger.png" alt=""></p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-14' href='slides_adv_authentication.html#/14'>◻</a></p>
<h2 id="rails"><a class="anchorlink" href="#rails"><span>6</span> Rails</a></h2></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-15' href='slides_adv_authentication.html#/15'>◻</a></p>
<h3 id="oauth"><a class="anchorlink" href="#oauth"><span>6.1</span> OAuth</a></h3><p>The gem <code>omniauth</code> helps you deal with OAuth2, OpenID, LDAP, and many
other authentication providers. The <a href="https://github.com/intridea/omniauth/wiki/List-of-Strategies">list of strategies</a>
is quite impressive. Think carefully about what services your users
are using, and which services might be useful to your app: could
you use Dropbox to authenticate, and also to deliver data directly
to your user's dropbox? Would it make sense to use Facebook or Twitter and also
send out messages that way? Or are your users very privacy conscious and
want to avoid Facebook and Google?</p><p>You will need the Gem <code>omniauth</code> and
additional gems for each provider. For example if you
want to use both Github and Stackoverflow for your web app geared
towards developers, you would need three gems:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">gem</span> <span class="s1">'omniauth'</span>
<span class="n">gem</span> <span class="s1">'omniauth-github'</span>
<span class="n">gem</span> <span class="s1">'omniauth-stackoverflow'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="gem 'omniauth'
gem 'omniauth-github'
gem 'omniauth-stackoverflow'
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-16' href='slides_adv_authentication.html#/16'>◻</a></p>
<h3 id="webauth"><a class="anchorlink" href="#webauth"><span>6.2</span> WebAuth</a></h3><p>Use the gems <code>devise</code> and <a href="https://github.com/ruby-passkeys/devise-passkeys">devise-passkeys</a></p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-17' href='slides_adv_authentication.html#/17'>◻</a></p>
<h3 id="json-web-tokens-jwt"><a class="anchorlink" href="#json-web-tokens-jwt"><span>6.3</span> JSON Web Tokens (JWT)</a></h3><p>Use the gem <code>jwt</code>
- <a href="https://github.com/lynndylanhurley/devise_token_auth">devise_token_auth</a> for token based authentication for API only Rails apps</p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-18' href='slides_adv_authentication.html#/18'>◻</a></p>
<h2 id="next-js"><a class="anchorlink" href="#next-js"><span>7</span> next.js</a></h2><p>The package <code>next-auth</code> provides several authentication methods.</p>
<ul>
<li>OAuth2</li>
<li><a href="https://next-auth.js.org/providers/email">E-Mail</a> "magic links"</li>
</ul>
<p>And it can save information to a database through an <a href="https://authjs.dev/reference/adapters">adapter</a>.</p><p>When you install the package you also need to set several
environment variables (for example through <code>.env</code>):</p><p>The URL of the application - this is needed to construct callback urls
for OAuth2. And a secret that will be used to sign certain tokens.
You can use <code>openssl rand -base64 32</code> to create a random string.</p><div class="interstitial code">
<pre><code class="highlight shell"><span class="nv">NEXTAUTH_URL</span><span class="o">=</span>http://localhost:3000
<span class="nv">NEXTAUTH_SECRET</span><span class="o">=</span>...
</code></pre>
<button class="clipboard-button" data-clipboard-text="NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=...
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-19' href='slides_adv_authentication.html#/19'>◻</a></p>
<h3 id="oauth2"><a class="anchorlink" href="#oauth2"><span>7.1</span> OAuth2</a></h3><p>For OAuth2 you have to configure two parties at the same time:</p>
<ul>
<li>the "authentication provider"</li>
<li>your own web app</li>
</ul>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-20' href='slides_adv_authentication.html#/20'>◻</a></p>
<h3 id="configuring-the-authentication-provider"><a class="anchorlink" href="#configuring-the-authentication-provider"><span>7.2</span> configuring the authentication provider</a></h3><p>You need to finde the right webpage that lets you configure the authentication provider.
For example at Github you find it under Settings, "for Developers", "create App".</p><p>You need to supply the following information:</p>
<ul>
<li>The URL of your app, for example <code>https://myapp.at</code></li>
<li>The callback URL for OAuth2, for example <code>https://myapp.at/api/auth/callback/github</code></li>
</ul>
<p>In the <a href="https://next-auth.js.org/getting-started/rest-api#getpost-apiauthcallbackprovider">documentation for auth-next</a>
you can see that the callback URL has the form <code>/api/auth/callback/:provider</code></p></div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-21' href='slides_adv_authentication.html#/21'>◻</a></p>
<h3 id="configuring-the-callback"><a class="anchorlink" href="#configuring-the-callback"><span>7.3</span> configuring the callback</a></h3><p>When using the app router, you need to create the file <code>app/api/auth/[...nextauth]/route.js</code></p><p>Here you need to import and configure one or several authentication providers.
This example shows github. See <code>node_modules/next-auth/providers/*.js</code> for a
list of the available providers.</p><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// File app/api/auth/[...nextauth]/route.js</span>
<span class="k">import</span> <span class="nx">NextAuth</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next-auth</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">GithubProvider</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">next-auth/providers/github</span><span class="dl">'</span><span class="p">;</span>
<span class="k">export</span> <span class="kd">const</span> <span class="nx">authOptions</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">providers</span><span class="p">:</span> <span class="p">[</span>
<span class="nc">GithubProvider</span><span class="p">({</span>
<span class="na">clientId</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">GITHUB_CLIENT_ID</span><span class="p">,</span>
<span class="na">clientSecret</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">GITHUB_CLIENT_SECRET</span><span class="p">,</span>
<span class="p">})</span>
<span class="p">]</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">handler</span> <span class="o">=</span> <span class="nc">NextAuth</span><span class="p">(</span><span class="nx">authOptions</span><span class="p">);</span>
<span class="k">export</span> <span class="p">{</span>
<span class="nx">handler</span> <span class="k">as</span> <span class="nx">GET</span><span class="p">,</span>
<span class="nx">handler</span> <span class="k">as</span> <span class="nx">POST</span>
<span class="p">};</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// File app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth';
import GithubProvider from 'next-auth/providers/github';
export const authOptions = {
providers: [
GithubProvider({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
})
]
};
const handler = NextAuth(authOptions);
export {
handler as GET,
handler as POST
};
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-22' href='slides_adv_authentication.html#/22'>◻</a></p>
<h3 id="link-to-sign-in-and-sign-out"><a class="anchorlink" href="#link-to-sign-in-and-sign-out"><span>7.4</span> link to sign in and sign out</a></h3><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// in a server component - no access to state</span>
<span class="k">import</span> <span class="p">{</span><span class="nx">authOptions</span><span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@/app/api/auth/[...nextauth]/route.js</span><span class="dl">"</span>
<span class="k">import</span> <span class="p">{</span><span class="nx">getServerSession</span><span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next-auth/next</span><span class="dl">"</span>
<span class="k">import</span> <span class="nx">Link</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next/link</span><span class="dl">"</span>
<span class="k">export</span> <span class="k">default</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">SignInStatus</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">session</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">getServerSession</span><span class="p">(</span><span class="nx">authOptions</span><span class="p">)</span>
<span class="k">if</span><span class="p">(</span><span class="nx">session</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="o"><></span>
<span class="nx">Signed</span> <span class="k">in</span> <span class="k">as</span> <span class="p">{</span><span class="nx">session</span><span class="p">.</span><span class="nx">user</span><span class="p">.</span><span class="nx">email</span><span class="p">}</span> <span class="o"><</span><span class="nx">br</span><span class="o">/></span>
<span class="o"><</span><span class="nx">Link</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/api/auth/signout</span><span class="dl">"</span><span class="o">></span><span class="nx">Sign</span> <span class="nx">out</span><span class="o"><</span><span class="sr">/Link</span><span class="err">>
</span> <span class="o"><</span><span class="nx">pre</span><span class="o">></span><span class="p">{</span><span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">session</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="mi">2</span><span class="p">)}</span><span class="o"><</span><span class="sr">/pre</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/</span><span class="err">>
</span> <span class="p">}</span>
<span class="k">return</span> <span class="o"><></span>
<span class="nx">Not</span> <span class="nx">signed</span> <span class="k">in</span> <span class="o"><</span><span class="nx">br</span><span class="o">/></span>
<span class="o"><</span><span class="nx">Link</span> <span class="nx">href</span><span class="o">=</span><span class="dl">"</span><span class="s2">/api/auth/signin</span><span class="dl">"</span><span class="o">></span><span class="nx">Sign</span> <span class="k">in</span><span class="o"><</span><span class="sr">/Link</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/</span><span class="err">>
</span><span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// in a server component - no access to state
import {authOptions} from "@/app/api/auth/[...nextauth]/route.js"
import {getServerSession} from "next-auth/next"
import Link from "next/link"
export default async function SignInStatus() {
const session = await getServerSession(authOptions)
if(session) {
return <>
Signed in as {session.user.email} <br/>
<Link href="/api/auth/signout">Sign out</Link>
<pre>{JSON.stringify(session, null, 2)}</pre>
</>
}
return <>
Not signed in <br/>
<Link href="/api/auth/signin">Sign in</Link>
</>
}
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-23' href='slides_adv_authentication.html#/23'>◻</a></p>
<h3 id="in-server-components"><a class="anchorlink" href="#in-server-components"><span>7.5</span> in server components</a></h3><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// in a server component - no access to state</span>
<span class="k">import</span> <span class="p">{</span><span class="nx">authOptions</span><span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@/app/api/auth/[...nextauth]/route.js</span><span class="dl">"</span>
<span class="k">import</span> <span class="p">{</span><span class="nx">getServerSession</span><span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next-auth/next</span><span class="dl">"</span>
<span class="k">export</span> <span class="k">default</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">ServerComponent</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">session</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">getServerSession</span><span class="p">(</span><span class="nx">authOptions</span><span class="p">)</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// in a server component - no access to state
import {authOptions} from "@/app/api/auth/[...nextauth]/route.js"
import {getServerSession} from "next-auth/next"
export default async function ServerComponent() {
const session = await getServerSession(authOptions)
...
}
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-24' href='slides_adv_authentication.html#/24'>◻</a></p>
<h3 id="in-client-components"><a class="anchorlink" href="#in-client-components"><span>7.6</span> in client components</a></h3><p>To have the session available in client components, we first
have to wrap the whole app in a <code>SessionProvider</code>. This needs
to happen in a client component. But how can we use
server components inside this client component?</p><p>We need three steps to get there:</p>
<ol>
<li><code>layout.js</code></li>
<li><code>ClientSessionProvider.client.js</code></li>
<li>code for a client component that needs to use the session</li>
</ol>
<p>We start off in <code>layout.js</code> in the main <code>app</code> folder, and use
the method of wrapping server components inside a client component
inside a server component mentioned <a href="https://backend-development.github.io/nextjs.html#you-can-pass-in-server-components-to-a-clientcomponent">before</a>.</p><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// app/layout.js</span>
<span class="k">import</span> <span class="nx">ClientSessionProvider</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@/components/ClientSessionProvider.client.js</span><span class="dl">'</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">RootLayout</span><span class="p">({</span> <span class="nx">children</span> <span class="p">})</span> <span class="p">{</span>
<span class="k">return </span><span class="p">(</span>
<span class="o"><</span><span class="nx">html</span> <span class="nx">lang</span><span class="o">=</span><span class="dl">"</span><span class="s2">en</span><span class="dl">"</span><span class="o">></span>
<span class="o"><</span><span class="nx">ClientSessionProvider</span><span class="o">></span>
<span class="o"><</span><span class="nx">body</span> <span class="nx">className</span><span class="o">=</span><span class="p">{</span><span class="nx">inter</span><span class="p">.</span><span class="nx">className</span><span class="p">}</span><span class="o">></span>
<span class="p">{</span><span class="nx">children</span><span class="p">}</span>
<span class="o"><</span><span class="sr">/body</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/ClientSessionProvider</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/html</span><span class="err">>
</span> <span class="p">)</span>
<span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// app/layout.js
import ClientSessionProvider from '@/components/ClientSessionProvider.client.js'
export default function RootLayout({ children }) {
return (
<html lang="en">
<ClientSessionProvider>
<body className={inter.className}>
{children}
</body>
</ClientSessionProvider>
</html>
)
}
">Copy</button>
</div>
<p>Then inside the client component we use the session provider:</p><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// components/ClientSessionProvider.client.js</span>
<span class="dl">"</span><span class="s2">use client</span><span class="dl">"</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">SessionProvider</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next-auth/react</span><span class="dl">"</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">ClientSessionProvider</span><span class="p">({</span> <span class="nx">children</span> <span class="p">})</span> <span class="p">{</span>
<span class="k">return </span><span class="p">(</span>
<span class="o"><</span><span class="nx">SessionProvider</span><span class="o">></span>
<span class="p">{</span><span class="nx">children</span><span class="p">}</span>
<span class="o"><</span><span class="sr">/SessionProvider</span><span class="err">>
</span> <span class="p">)</span>
<span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// components/ClientSessionProvider.client.js
"use client"
import { SessionProvider } from "next-auth/react"
export default function ClientSessionProvider({ children }) {
return (
<SessionProvider>
{children}
</SessionProvider>
)
}
">Copy</button>
</div>
<p>Now we can use the session in any client component:</p><div class="interstitial code">
<pre><code class="highlight javascript"><span class="c1">// components/SomeComponent.client.js</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">useSession</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">next-auth/react</span><span class="dl">"</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nf">SomeComponent</span><span class="p">({})</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="na">data</span><span class="p">:</span> <span class="nx">session</span><span class="p">,</span> <span class="nx">status</span> <span class="p">}</span> <span class="o">=</span> <span class="nf">useSession</span><span class="p">();</span>
<span class="p">...</span>
<span class="k">return </span><span class="p">(</span>
<span class="o"><></span>
<span class="o"><</span><span class="nx">h1</span><span class="o">></span><span class="p">{</span> <span class="nx">status</span> <span class="o">!==</span> <span class="dl">"</span><span class="s2">authenticated</span><span class="dl">"</span> <span class="p">?</span> <span class="nx">status</span> <span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">(</span><span class="nx">session</span><span class="p">)}</span><span class="o"><</span><span class="sr">/h1</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/</span><span class="err">>
</span> <span class="p">)</span>
<span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="// components/SomeComponent.client.js
import { useSession } from "next-auth/react"
export default function SomeComponent({}) {
const { data: session, status } = useSession();
...
return (
<>
<h1>{ status !== "authenticated" ? status : JSON.stringify(session)}</h1>
</>
)
}
">Copy</button>
</div>
</div>
<div class='slide'>
<p class='slide_break_block'><a class='slide_break' id='slide-25' href='slides_adv_authentication.html#/25'>◻</a></p>
<h2 id="further-reading"><a class="anchorlink" href="#further-reading"><span>8</span> Further Reading</a></h2>
<ul>
<li><a href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/">What Are Refresh Tokens and How to Use Them Securely</a></li>
</ul>
</div>
</div>
</div>
</main>
<hr class="hide" />
<footer id="page_footer">
<div class="wrapper">
<p class="copyright">published under <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/at/deed.de">creative commons by-nc-sa</a> in 2012-2025 by <a href="https://brigitte-jellinek.at">Brigitte Jellinek</a>.
</p>
<p>If you want to contribute: <a href="https://github.com/backend-development/backend-development-textbook/fork">fork the source on github</a>
</p>
<p>Favicon "backend development" by Arkinasi from <a href="https://thenounproject.com/browse/icons/term/backend-development/" target="_blank" title="backend development Icons">Noun Project</a> (CC BY 3.0)</p>
</div>
</footer>
</body>
</html>