Skip to content

Commit 7ff57a3

Browse files
authored
Merge pull request #47 from creode/fix/login_url_redirection
fix: fixes an issue with validation of redirection urls, adds documen…
2 parents 1b8e9aa + 07ea0ae commit 7ff57a3

5 files changed

Lines changed: 84 additions & 4 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ prepros-6.config
3535
.ddev
3636

3737
# Test Caching / Logging
38+
tests/.env
3839
tests/_craft/config/project/*
3940
tests/_craft/storage/logs/*
4041
tests/_output/*

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,36 @@ We are also aware with this plugin that sometimes you may want to inject the exi
9494

9595
`{% include 'magic-login/_login-form' %}`
9696

97+
### Redirecting after a successful Magic Login
98+
99+
When generating a magic login link, you can control where the user is redirected after they click the emailed link and authentication completes.
100+
101+
To do this, include a hidden field named `magicLoginRedirectUrl` in the POST that requests the magic link.
102+
103+
```twig
104+
<form method="post">
105+
{{ actionInput('magic-login/magic-login/login') }}
106+
{{ csrfInput() }}
107+
108+
{{ hiddenInput('magicLoginRedirectUrl', url('account')) }}
109+
110+
<input type="email" name="email">
111+
<button type="submit">Send link</button>
112+
</form>
113+
```
114+
115+
If `magicLoginRedirectUrl` is not provided (or isn’t considered valid), the plugin will fall back to Craft’s `postLoginRedirect` general config setting.
116+
117+
**Valid redirect URLs**
118+
119+
The `magicLoginRedirectUrl` value must be a “full” URL. That means one of:
120+
121+
- Absolute URL (includes a scheme), e.g. `https://example.com/account`
122+
- Root-relative URL (starts with `/`), e.g. `/account`
123+
- Protocol-relative URL (starts with `//`), e.g. `//example.com/account`
124+
125+
Values like `account` (no leading `/`) will be treated as invalid and the plugin will fall back to `postLoginRedirect`.
126+
97127
## Technical Features / Under the Hood
98128

99129
### Password Generation

src/services/MagicLoginAuthService.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Craft;
1414

1515
use craft\base\Component;
16+
use craft\helpers\UrlHelper;
1617
use creode\magiclogin\MagicLogin;
1718
use creode\magiclogin\models\AuthModel;
1819
use creode\magiclogin\records\AuthRecord;
@@ -92,9 +93,12 @@ public function createMagicLogin(string $userNameOrEmail)
9293
$record->userId = $user->id;
9394
$record->publicKey = $publicKey;
9495
$record->privateKey = $privateKey;
95-
$record->redirectUrl = Craft::$app
96-
->getRequest()
97-
->getValidatedBodyParam('magicLoginRedirectUrl') ?? $generalConfig->postLoginRedirect;
96+
$redirectUrl = Craft::$app->getRequest()->getBodyParam('magicLoginRedirectUrl');
97+
if (is_string($redirectUrl) && UrlHelper::isFullUrl($redirectUrl)) {
98+
$record->redirectUrl = $redirectUrl;
99+
} else {
100+
$record->redirectUrl = $generalConfig->postLoginRedirect;
101+
}
98102
$record->save();
99103

100104
// Generate Datetime for current dateCreated and use it's timestamp.

test-config/project/project.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ system:
2020
edition: pro
2121
live: true
2222
name: 'Magic login testing'
23-
schemaVersion: 5.6.0.2
23+
schemaVersion: 5.9.0.8
2424
timeZone: America/Los_Angeles

tests/functional/LoginFormTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?php
22

3+
/**
4+
* Functional tests for Magic Login login form.
5+
*/
6+
37
namespace creode\magiclogintests\acceptance;
48

59
use Craft;
@@ -8,9 +12,14 @@
812
use craft\elements\User;
913
use creode\magiclogin\records\AuthRecord;
1014

15+
/**
16+
* Tests the Magic Login frontend login form workflow.
17+
*/
1118
class LoginFormTest extends BaseFunctionalTest
1219
{
1320
/**
21+
* Functional test actor.
22+
*
1423
* @var \FunctionalTester
1524
*/
1625
protected $tester;
@@ -200,8 +209,44 @@ public function testSuccessfulLogin()
200209
$this->assertEquals($emailSubject, $magicLoginEmail->getSubject());
201210
}
202211

212+
/**
213+
* Tests that the magicLoginRedirectUrl POST param is persisted on the auth record,
214+
* and will be used after the user clicks their magic link.
215+
*
216+
* @return void
217+
*/
218+
public function testSuccessfulLoginPersistsProvidedRedirectUrl()
219+
{
220+
$validUser = User::findOne();
221+
222+
AuthRecord::deleteAll();
223+
224+
$authRecords = AuthRecord::find()->all();
225+
226+
$targetRedirect = '/after-magic-login';
227+
228+
$this->tester->amOnPage('/magic-login/login');
229+
$this->tester->submitForm(
230+
'#magic-login-form',
231+
[
232+
'email' => $validUser->email,
233+
'magicLoginRedirectUrl' => $targetRedirect,
234+
],
235+
'submitButton'
236+
);
237+
238+
$updatedAuthRecords = AuthRecord::find()->all();
239+
$this->assertEquals(count($authRecords) + 1, count($updatedAuthRecords));
240+
241+
$authRecord = AuthRecord::find()->one();
242+
$this->assertNotNull($authRecord, 'AuthRecord should be created for a valid login request.');
243+
$this->assertEquals($targetRedirect, $authRecord->redirectUrl);
244+
}
245+
203246
/**
204247
* Tests that we have a rate limit setup for Magic Login.
248+
*
249+
* @return void
205250
*/
206251
public function testMagicLoginEmailRateLimit()
207252
{

0 commit comments

Comments
 (0)