diff --git a/app/config/auth.php b/app/config/auth.php
index 11b89dd9ec..170b87344e 100644
--- a/app/config/auth.php
+++ b/app/config/auth.php
@@ -10,6 +10,13 @@ return [
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateSession',
'enabled' => true,
],
+ 'magic-url' => [
+ 'name' => 'Magic URL',
+ 'key' => 'usersAuthMagicURL',
+ 'icon' => '/images/users/magic-url.png',
+ 'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateMagicURLSession',
+ 'enabled' => true,
+ ],
'anonymous' => [
'name' => 'Anonymous',
'key' => 'usersAuthAnonymous',
diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php
index 9649c5e2fd..a18d851052 100644
--- a/app/controllers/api/account.php
+++ b/app/controllers/api/account.php
@@ -616,6 +616,7 @@ App::post('/v1/account/sessions/magic-url')
->desc('Create Magic URL session')
->groups(['api', 'account'])
->label('scope', 'public')
+ ->label('auth.type', 'magic-url')
->label('sdk.auth', [])
->label('sdk.namespace', 'account')
->label('sdk.method', 'createMagicURLSession')
@@ -730,8 +731,12 @@ App::post('/v1/account/sessions/magic-url')
throw new Exception('Failed to save user to DB', 500);
}
+ if(empty($url)) {
+ $url = $request->getProtocol().'://'.$request->getHostname().'/auth/magic-url/success';
+ }
+
$url = Template::parseURL($url);
- $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire]);
+ $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire, 'project' => $project->getId()]);
$url = Template::unParseURL($url);
$mails
@@ -849,6 +854,10 @@ App::put('/v1/account/sessions/magic-url')
if (false === $user) {
throw new Exception('Failed saving user to DB', 500);
}
+
+ if (!$projectDB->deleteDocument($token)) {
+ throw new Exception('Failed to remove login token from DB', 500);
+ }
$audits
->setParam('userId', $user->getId())
diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php
index f3eeb71c94..5805473b9b 100644
--- a/app/controllers/web/home.php
+++ b/app/controllers/web/home.php
@@ -197,6 +197,35 @@ App::get('/auth/oauth2/success')
;
});
+App::get('/auth/magic-url')
+ ->groups(['web', 'home'])
+ ->label('permission', 'public')
+ ->label('scope', 'home')
+ ->inject('request')
+ // ->inject('response')
+ ->inject('layout')
+ ->action(function ($request, $layout) {
+ /** @var Utopia\Swoole\Request $request */
+ /** @var Utopia\Swoole\Response $response */
+
+ $page = new View(__DIR__.'/../../views/home/auth/magicURL.phtml');
+
+ $userId = $request->getQuery('userId');
+ $secret = $request->getQuery('secret');
+ $project = $request->getQuery('project');
+ $page
+ ->setParam('userId', $userId)
+ ->setParam('secret', $secret)
+ ->setParam('project', $project);
+
+ $layout
+ ->setParam('title', APP_NAME)
+ ->setParam('body', $page)
+ ->setParam('header', [])
+ ->setParam('footer', [])
+ ;
+ });
+
App::get('/auth/oauth2/failure')
->groups(['web', 'home'])
->label('permission', 'public')
diff --git a/app/views/home/auth/magicURL.phtml b/app/views/home/auth/magicURL.phtml
new file mode 100644
index 0000000000..1b07a29513
--- /dev/null
+++ b/app/views/home/auth/magicURL.phtml
@@ -0,0 +1,35 @@
+
+
Missing Redirect URL
+
Your Magic URL login flow is missing a proper redirect URL. Please check the
+ Magic URL docs
+ and send request for new session with a valid redirect URL.
+
+
+
+
\ No newline at end of file
diff --git a/public/dist/scripts/app-all.js b/public/dist/scripts/app-all.js
index e4db3f821f..b9e75f8b81 100644
--- a/public/dist/scripts/app-all.js
+++ b/public/dist/scripts/app-all.js
@@ -2239,7 +2239,7 @@ return slf.renderToken(tokens,idx,opts);}
md.renderer.rules.strong_open=renderEm;md.renderer.rules.strong_close=renderEm;return md;},true);})(window);(function(window){"use strict";window.ls.container.set('rtl',function(){var rtlStock="^ا^ب^ت^ث^ج^ح^خ^د^ذ^ر^ز^س^ش^ص^ض^ط^ظ^ع^غ^ف^ق^ك^ل^م^ن^ه^و^ي^א^ב^ג^ד^ה^ו^ז^ח^ט^י^כ^ך^ל^מ^ם^נ^ן^ס^ע^פ^ף^צ^ץ^ק^ר^ש^ת^";var special=["\n"," "," ","״",'"',"_","'","!","@","#","$","^","&","%","*","(",")","+","=","-","[","]","\\","/","{","}","|",":","<",">","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;i","?",",",".","0","1","2","3","4","5","6","7","8","9"];var isRTL=function(value){for(var i=0;iclient->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'email' => $email,
+ // 'url' => 'http://localhost/magiclogin',
+ ]);
+
+ $this->assertEquals(201, $response['headers']['status-code']);
+ $this->assertNotEmpty($response['body']['$id']);
+ $this->assertEmpty($response['body']['secret']);
+ $this->assertIsNumeric($response['body']['expire']);
+
+ $userId = $response['body']['userId'];
+
+ $lastEmail = $this->getLastEmail();
+ $this->assertEquals($email, $lastEmail['to'][0]['address']);
+ $this->assertEquals('Login', $lastEmail['subject']);
+
+ $token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
+
+ $expireTime = strpos($lastEmail['text'], 'expire='.$response['body']['expire'], 0);
+
+ $this->assertNotFalse($expireTime);
+
+ $secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0);
+
+ $this->assertNotFalse($secretTest);
+
+ $userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0);
+
+ $this->assertNotFalse($userIDTest);
+
+ /**
+ * Test for FAILURE
+ */
+ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'email' => $email,
+ 'url' => 'localhost/magiclogin',
+ ]);
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'email' => $email,
+ 'url' => 'http://remotehost/magiclogin',
+ ]);
+
+ $this->assertEquals(400, $response['headers']['status-code']);
+
+ $data['token'] = $token;
+ $data['id'] = $userId;
+
+ return $data;
+ }
+
+ /**
+ * @depends testCreateMagicUrl
+ */
+ public function testCreateSessionWithMagicUrl($data):array
+ {
+ $id = $data['id'] ?? '';
+ $token = $data['token'] ?? '';
+
+ /**
+ * Test for SUCCESS
+ */
+ $response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'userId' => $id,
+ 'secret' => $token,
+ ]);
+
+ $this->assertEquals(201, $response['headers']['status-code']);
+ $this->assertIsArray($response['body']);
+ $this->assertNotEmpty($response['body']);
+ $this->assertNotEmpty($response['body']['$id']);
+ $this->assertNotEmpty($response['body']['userId']);
+
+ /**
+ * Test for FAILURE
+ */
+ $response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'userId' => 'ewewe',
+ 'secret' => $token,
+ ]);
+
+ $this->assertEquals(404, $response['headers']['status-code']);
+
+ $response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
+ 'origin' => 'http://localhost',
+ 'content-type' => 'application/json',
+ 'x-appwrite-project' => $this->getProject()['$id'],
+ ]), [
+ 'userId' => $id,
+ 'secret' => 'sdasdasdasd',
+ ]);
+
+ $this->assertEquals(401, $response['headers']['status-code']);
+
+ return $data;
+ }
}
\ No newline at end of file