{"_id":"56123c063cf4bc0d00554e37","project":"55edea207145f717001ac12c","category":{"_id":"55ffceca0e2b090d008633b2","pages":["55ffcedffeaf310d007dd6d6","55ffd0879e7ccf0d000a1e09","55ffddd1feaf310d007dd6e8","55ffdee4feaf310d007dd6ea","55ffe2336932a00d00ba7abf","55ffeb898c0c9d0d00dcacd0","55fff74c6932a00d00ba7b0c","55fff9df0c703d1900952fe1","55fffecb6932a00d00ba7b1b","55ffffd49e7ccf0d000a1e49","560001159e7ccf0d000a1e4d","560004126932a00d00ba7b2a","560006ef0c703d1900952ffc","560009fa8c0c9d0d00dcad0d","5601137f9137690d00335697","560120f34ea1b40d003bf1a4","5601221bf01fb90d00d4bf7e","5601274781a9670d006d1514","5601292881a9670d006d1516","56012ab3f01fb90d00d4bf88","56012c754ea1b40d003bf1b9","56012d824ea1b40d003bf1c0","56053e9df6b86e0d00284ad1","560541907c8e580d0001afe8","56123c063cf4bc0d00554e37","561264c70157131900b45863","561272d60157131900b45870","5612796d09bdc51700696fdf","56138c7a6fd7042b008f0187","5613a63d46c35f3500773c06","5613a79a44d6662b0071f5d9"],"project":"55edea207145f717001ac12c","version":"55edea207145f717001ac12f","__v":31,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-09-21T09:32:58.200Z","from_sync":false,"order":0,"slug":"sdk","title":"SDK"},"version":{"_id":"55edea207145f717001ac12f","project":"55edea207145f717001ac12c","__v":11,"createdAt":"2015-09-07T19:48:48.670Z","releaseDate":"2015-09-07T19:48:48.670Z","categories":["55edea217145f717001ac130","55ffa8038c0c9d0d00dcac72","55ffbaa48c0c9d0d00dcac88","55ffbd3e8c0c9d0d00dcac8b","55ffbee40e2b090d00863393","55ffc4306932a00d00ba7a85","55ffc66bfeaf310d007dd6c8","55ffc9c2feaf310d007dd6d1","55ffceca0e2b090d008633b2","560111b06811d00d00ceb34e","560262e74f15002100ee4445"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"user":"55ede9ed1452cd0d009e5e6b","__v":21,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-10-05T08:59:50.884Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":29,"body":"After a successful authentication Rublon will redirect the user's browser to the callback URL. The callback flow continues the authentication process, i.e. the finalization of the authentication (logging in or identity confirmation).\n\n## Input params\n\nThe callback URL will receive its input arguments in the URL address itself (*query string*).\n[block:html]\n{\n  \"html\": \"<div>\\n\\n  <!-- Nav tabs -->\\n  <ul class=\\\"nav nav-tabs langnav\\\" role=\\\"tablist\\\">\\n    <li role=\\\"presentation\\\" class=\\\"active\\\"><a href=\\\"#php\\\" aria-controls=\\\"php\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">PHP</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#net\\\" aria-controls=\\\"net\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">.NET</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#java\\\" aria-controls=\\\"java\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">Java</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#python\\\" aria-controls=\\\"python\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">Python</a></li>\\n  </ul>\\n\\n  <!-- Tab panes -->\\n  <div class=\\\"tab-content\\\">\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane active\\\" id=\\\"php\\\">\\n<table>\\n\\t<caption>Callback URL arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>state</code></td><td>string</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\\n\\t\\t<tr><td><code>token</code></td><td>string</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\\n\\t</tbody>\\n</table>    \\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"net\\\">\\n<table>\\n\\t<caption>Callback URL arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>state</code></td><td>string</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\\n\\t\\t<tr><td><code>token</code></td><td>string</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\\n\\t</tbody>\\n</table>   \\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"java\\\">\\n<table>\\n\\t<caption>Callback URL arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>state</code></td><td>String</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\\n\\t\\t<tr><td><code>token</code></td><td>String</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\\n\\t</tbody>\\n</table>\\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"python\\\">\\n<table>\\n\\t<caption>Callback URL arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>state</code></td><td>str</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\\n\\t\\t<tr><td><code>token</code></td><td>str</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\\n\\t</tbody>\\n</table>\\n    </div>\\n  </div>\\n\\n</div>\\n<style>\\n.langnav > li > a {\\n    padding: 3px 15px;\\n}\\ncaption{\\nmargin:10px;\\n}\\n</style>\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Notice: If the callback URL has been set to e.g. `http://example.com/twofactor/auth/`, the params will be appended to the URL address: \\n\\n<pre>`http://example.com/twofactor/auth/?state=ok&token=Kmad4hAS...d`</pre>\\n\\nIf your callback URL should be formed differently (e.g. when using mod_rewrite), you can set the callback URL's template using the meta-tags: `%token%` and `%state%`, like so:\\n\\n<pre>`http://example.com/twofactor/auth/%state%/%token%`</pre>\"\n}\n[/block]\n## Authentication verification\n[block:html]\n{\n  \"html\": \"<div>\\n\\n  <!-- Nav tabs -->\\n  <ul class=\\\"nav nav-tabs langnav\\\" role=\\\"tablist\\\">\\n    <li role=\\\"presentation\\\" class=\\\"active\\\"><a href=\\\"#php2\\\" aria-controls=\\\"php\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">PHP</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#net2\\\" aria-controls=\\\"net\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">.NET</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#java2\\\" aria-controls=\\\"java\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">Java</a></li>\\n    <li role=\\\"presentation\\\"><a href=\\\"#python2\\\" aria-controls=\\\"python\\\" role=\\\"tab\\\" data-toggle=\\\"tab\\\">Python</a></li>\\n  </ul>\\n\\n  <!-- Tab panes -->\\n  <div class=\\\"tab-content\\\">\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane active\\\" id=\\\"php2\\\">\\n      <br/>\\n      <p>After the callback is invoked, for proper finalization of the authentication process you need to instantiate a <code>Rublon2FactorCallback</code> class object.</p>\\n      <table>\\n\\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>$rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\\n\\t</tbody>\\n</table> \\n      <p>Next, the <code>Rublon2FactorCallback::call()</code> method should be called. It takes two arguments.</p>\\n\\n<table>\\n\\t<caption><code>Rublon2FactorCallback::call</code> method arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>$successHandler</code></td><td>callable</td><td>Name of a function/method, or an anonymous function/closure, which will be invoked on successful verification of the process, finalizing the authentication (logging the user in or confirming the user's identity for some operation).</td></tr>\\n\\t\\t<tr><td><code>$cancelHandler</code></td><td>callable</td><td>Name of a function/method, or an anonymous function/closure, which will be invoked on receiving the <code>cancel</code> state to cancel the authentication transaction.</td></tr>\\n\\t</tbody>\\n</table>\\n\\n<table>\\n\\t<caption>Arguments of the <code>$successHandler</code> function, passed to the <code>Rublon2FactorCallback::call</code> method</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>$userId</code></td><td>string</td><td>The user's unique Id in the integrated system, given as an argument to the <code>Rublon2Factor::auth</code> method, whose authentication is being confirmed by Rublon\\n</td></tr>\\n\\t\\t<tr><td><code>$callback</code></td><td>Rublon2FactorCallback</td><td>An instance of the <code>Rublon2FactorCallback</code> class</td></tr>\\n\\t</tbody>\\n</table>\\n      \\n<table>\\n\\t<caption>Argument of the <code>$cancelHandler</code> function, passed to the <code>Rublon2FactorCallback::call</code> method</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>$callback</code></td><td>Rublon2FactorCallback</td><td>An instance of the <code>Rublon2FactorCallback</code> class</td></tr>\\n\\t</tbody>\\n</table>      \\n     <h3>Example PHP code</h3>\\n<p>An example of the <code>Rublon2FactorCallback</code> class usage in the callback:</p>\\n<!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\\\"ng-scope\\\" ng-switch-when=\\\"code\\\"><div type=\\\"section.type\\\" ng-model=\\\"section.data\\\" class=\\\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\\\">\\n  <div class=\\\"code-tabs ng-hide\\\" ng-show=\\\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\\\">\\n    <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope tab on\\\" ng-class=\\\"{tab: true, on:$index==current, off:$index!=current}\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\">\\n      <a href=\\\"\\\" ng-click=\\\"choose($index)\\\">\\n        <!-- ngIf: tab.status -->\\n        <!-- ngIf: !tab.status --><span class=\\\"ng-scope ng-binding\\\" ng-if=\\\"!tab.status\\\">\\n          PHP\\n        </span><!-- end ngIf: !tab.status -->\\n      </a><span class=\\\"ng-hide\\\" ng-hide=\\\"$last\\\">·</span>\\n    </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n  </div>\\n\\n  <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\" ng-show=\\\"$index==current\\\">\\n  <pre class=\\\"cm-s-neo\\\" data-mode=\\\"php\\\"><span class=\\\"cm-meta\\\">&lt;?</span>\\n<span class=\\\"cm-variable-2\\\">$rublon</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">new</span> <span class=\\\"cm-variable\\\">Rublon2Factor</span>(<span class=\\\"cm-string\\\">\\\"</span><span class=\\\"cm-string\\\">your_system_token\\\"</span>, <span class=\\\"cm-string\\\">\\\"</span><span class=\\\"cm-string\\\">your_access_key\\\"</span>);\\n\\n<span class=\\\"cm-keyword\\\">try</span> {\\n  <span class=\\\"cm-variable-2\\\">$callback</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">new</span> <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span>(<span class=\\\"cm-variable-2\\\">$rublon</span>);\\n  <span class=\\\"cm-variable-2\\\">$callback</span><span class=\\\"cm-operator\\\">-&gt;</span><span class=\\\"cm-variable\\\">call</span>(\\n    <span class=\\\"cm-variable-2\\\">$successHandler</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">function</span>(<span class=\\\"cm-variable-2\\\">$userId</span>, <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> <span class=\\\"cm-variable-2\\\">$callback</span>) {\\n      <span class=\\\"cm-comment\\\">// The user is finally logged in</span>\\n      <span class=\\\"cm-variable-2\\\">$_SESSION</span>[<span class=\\\"cm-string\\\">\\\"</span><span class=\\\"cm-string\\\">user\\\"</span>] <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-variable-2\\\">$userId</span>;\\n    },\\n    <span class=\\\"cm-variable-2\\\">$cancelHandler</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">function</span>(<span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> <span class=\\\"cm-variable-2\\\">$callback</span>) {\\n      <span class=\\\"cm-comment\\\">// Cancel the authentication process</span>\\n      <span class=\\\"cm-builtin\\\">header</span>(<span class=\\\"cm-string\\\">\\\"</span><span class=\\\"cm-string\\\">Location: /login\\\"</span>);\\n      <span class=\\\"cm-keyword\\\">exit</span>;\\n    }\\n  );\\n  \\n  <span class=\\\"cm-comment\\\">// The authentication process was successful</span>\\n  <span class=\\\"cm-builtin\\\">header</span>(<span class=\\\"cm-string\\\">\\\"</span><span class=\\\"cm-string\\\">Location: /dashboard\\\"</span>);\\n  <span class=\\\"cm-keyword\\\">exit</span>;\\n\\n} <span class=\\\"cm-keyword\\\">catch</span> (<span class=\\\"cm-variable\\\">RublonException</span> <span class=\\\"cm-variable-2\\\">$e</span>) {\\n  <span class=\\\"cm-comment\\\">// Please handle this error in the better way:</span>\\n  <span class=\\\"cm-keyword\\\">die</span>(<span class=\\\"cm-variable-2\\\">$e</span><span class=\\\"cm-operator\\\">-&gt;</span><span class=\\\"cm-variable\\\">getMessage</span>());\\n}</pre>\\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html -->      \\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"net2\\\">\\n      <br/>\\n      <p>After the callback is invoked, for proper finalization of the authentication process you need to create a <code>Rublon2FactorCallback</code> subclass instance. Because the <code>Rublon2FactorCallback</code> class in abstract you need to create a subclass that implement needed methods which depend on your system details.</p>\\n      <table>\\n\\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\\n\\t</tbody>\\n</table> \\n      \\n      <p>Next, the <code>Rublon2FactorCallback.Call()</code> method should be called.</p>\\n<p>The following abstract methods should be implemented in a subclass.</p>\\n<ul>\\n  <li><code>string getState()</code> - returns the \\\"state\\\" parameter from the HTTP GET request.</li>\\n\\t<li><code>string getAccessToken()</code> - returns the \\\"token\\\" parameter from the HTTP GET request.</li>\\n<li><code>void handleCancel()</code> - called when the state parameter is not \\\"ok\\\" nor \\\"error\\\".</li>\\n<li><code>void handleError()</code> - called when the state parameter value is \\\"error\\\".</li>\\n<li><code>void userAuthenticated(string userId)</code> - handle the authenticated user with given user's local ID.</li>\\n</ul>\\n<h3>Example .NET code </h3> \\n<p>An example implementation of the <code>Rublon2FactorCallback</code> class and usage in the callback:</p>\\n  <!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\\\"ng-scope\\\" ng-switch-when=\\\"code\\\"><div type=\\\"section.type\\\" ng-model=\\\"section.data\\\" class=\\\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\\\">\\n  <div class=\\\"code-tabs ng-hide\\\" ng-show=\\\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\\\">\\n    <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope tab on\\\" ng-class=\\\"{tab: true, on:$index==current, off:$index!=current}\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\">\\n      <a href=\\\"\\\" ng-click=\\\"choose($index)\\\">\\n        <!-- ngIf: tab.status -->\\n        <!-- ngIf: !tab.status --><span class=\\\"ng-scope ng-binding\\\" ng-if=\\\"!tab.status\\\">\\n          C#\\n        </span><!-- end ngIf: !tab.status -->\\n      </a><span class=\\\"ng-hide\\\" ng-hide=\\\"$last\\\">·</span>\\n    </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n  </div>\\n\\n  <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\" ng-show=\\\"$index==current\\\">\\n  <pre class=\\\"cm-s-neo\\\" data-mode=\\\"csharp\\\"><span class=\\\"cm-variable\\\">class</span> <span class=\\\"cm-variable\\\">Callback</span> : <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> \\n{\\n    <span class=\\\"cm-variable\\\">protected</span> <span class=\\\"cm-variable\\\">override</span> <span class=\\\"cm-variable\\\">string</span> <span class=\\\"cm-variable\\\">getState</span>() \\n    {\\n        <span class=\\\"cm-variable\\\">return</span> <span class=\\\"cm-variable\\\">Request</span>.<span class=\\\"cm-variable\\\">Params</span>[<span class=\\\"cm-variable\\\">PARAMETER_STATE</span>];\\n    }\\n    \\n    <span class=\\\"cm-variable\\\">protected</span> <span class=\\\"cm-variable\\\">override</span> <span class=\\\"cm-variable\\\">string</span> <span class=\\\"cm-variable\\\">getAccessToken</span>() \\n    {\\n        <span class=\\\"cm-variable\\\">return</span> <span class=\\\"cm-variable\\\">Request</span>.<span class=\\\"cm-variable\\\">Params</span>[<span class=\\\"cm-variable\\\">PARAMETER_ACCESS_TOKEN</span>];\\n    }\\n    \\n    <span class=\\\"cm-variable\\\">protected</span> <span class=\\\"cm-variable\\\">override</span> <span class=\\\"cm-variable\\\">void</span> <span class=\\\"cm-variable\\\">handleCancel</span>() \\n    {\\n        <span class=\\\"cm-variable\\\">Response</span>.<span class=\\\"cm-variable\\\">Redirect</span>(<span class=\\\"cm-string\\\">\\\"/Login\\\"</span>);\\n    }\\n    \\n    <span class=\\\"cm-variable\\\">protected</span> <span class=\\\"cm-variable\\\">override</span> <span class=\\\"cm-variable\\\">void</span> <span class=\\\"cm-variable\\\">handleError</span>() \\n    {\\n        <span class=\\\"cm-variable\\\">Response</span>.<span class=\\\"cm-variable\\\">Redirect</span>(<span class=\\\"cm-string\\\">\\\"/Login/?msg=rublon-error\\\"</span>);\\n    }\\n    \\n    <span class=\\\"cm-variable\\\">protected</span> <span class=\\\"cm-variable\\\">override</span> <span class=\\\"cm-variable\\\">void</span> <span class=\\\"cm-variable\\\">userAuthenticated</span>(<span class=\\\"cm-variable\\\">string</span> <span class=\\\"cm-variable\\\">userId</span>) \\n    {\\n        <span class=\\\"cm-variable\\\">Session</span>[<span class=\\\"cm-string\\\">\\\"loggedUsed\\\"</span>] <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-variable\\\">User</span>.<span class=\\\"cm-variable\\\">GetById</span>(<span class=\\\"cm-variable\\\">userId</span>);\\n        <span class=\\\"cm-variable\\\">Response</span>.<span class=\\\"cm-variable\\\">Redirect</span>(<span class=\\\"cm-string\\\">\\\"/\\\"</span>);\\n    }\\n}\\n\\n...\\n\\n<span class=\\\"cm-variable\\\">Rublon2Factor</span> <span class=\\\"cm-variable\\\">rublon</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-variable\\\">new</span> <span class=\\\"cm-variable\\\">Rublon2Factor</span>\\n(\\n    <span class=\\\"cm-string\\\">\\\"A69FC450848B4B94A040416DC4421523\\\"</span>,\\n    <span class=\\\"cm-string\\\">\\\"bLS6NDP7pGjg346S4IHqTHgQQjjSLw3CyApvz5iRjYzgIPN4e9EOi1cQJLrTlvLoHY8zeqg4ILrItYidKJ6JjEUZaA6pR1tZMwSZ\\\"</span>\\n);\\n\\n<span class=\\\"cm-variable\\\">try</span> \\n{\\n    <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> <span class=\\\"cm-variable\\\">callback</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-variable\\\">new</span> <span class=\\\"cm-variable\\\">Callback</span>(<span class=\\\"cm-variable\\\">rublon</span>);\\n    <span class=\\\"cm-variable\\\">callback</span>.<span class=\\\"cm-variable\\\">Call</span>();\\n} \\n<span class=\\\"cm-variable\\\">catch</span> (<span class=\\\"cm-variable\\\">CallbackException</span> <span class=\\\"cm-variable\\\">ex</span>) \\n{\\n    <span class=\\\"cm-comment\\\">// Please handle this error in the better way:</span>\\n    <span class=\\\"cm-variable\\\">throw</span>;\\n}</pre>\\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html -->    \\n      \\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"java2\\\">\\n      <br/>\\n      <p>After the callback is invoked, for proper finalization of the authentication process you need to create a <code>Rublon2FactorCallback</code> subclass instance. Because the <code>Rublon2FactorCallback</code> class in abstract you need to create a subclass\\nthat implement needed methods which depend on your system details.</p>\\n      <table>\\n\\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\\n\\t<thead><tr>\\n\\t\\t<th>Name</th>\\n\\t\\t<th>Type</th>\\n\\t\\t<th>Description</th>\\n\\t</tr></thead>\\n\\t<tbody>\\n\\t\\t<tr><td><code>rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\\n\\t</tbody>\\n</table> \\n      \\n      <p>Next, the <code>Rublon2FactorCallback.call()</code> method should be called.</p>\\n<p>The following abstract methods should be implemented in a subclass.</p>\\n<ul>\\n  <li><code>String getState()</code> - returns the \\\"state\\\" parameter from the HTTP GET request.</li>\\n\\t<li><code>String getAccessToken()</code> - returns the \\\"token\\\" parameter from the HTTP GET request.</li>\\n<li><code>void handleCancel()</code> - called when the state parameter is not \\\"ok\\\" nor \\\"error\\\".</li>\\n<li><code>void handleError()</code> - called when the state parameter value is \\\"error\\\".</li>\\n<li><code>void userAuthenticated(String userId)</code> - handle the authenticated user with given user's local ID.</li>\\n</ul>\\n<h3>Example JAVA code </h3> \\n<p>An example implementation of the <code>Rublon2FactorCallback</code> class and usage in the callback:</p>      \\n<!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\\\"ng-scope\\\" ng-switch-when=\\\"code\\\"><div type=\\\"section.type\\\" ng-model=\\\"section.data\\\" class=\\\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\\\">\\n  <div class=\\\"code-tabs ng-hide\\\" ng-show=\\\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\\\">\\n    <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope tab on\\\" ng-class=\\\"{tab: true, on:$index==current, off:$index!=current}\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\">\\n      <a href=\\\"\\\" ng-click=\\\"choose($index)\\\">\\n        <!-- ngIf: tab.status -->\\n        <!-- ngIf: !tab.status --><span class=\\\"ng-scope ng-binding\\\" ng-if=\\\"!tab.status\\\">\\n          Java\\n        </span><!-- end ngIf: !tab.status -->\\n      </a><span class=\\\"ng-hide\\\" ng-hide=\\\"$last\\\">·</span>\\n    </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n  </div>\\n\\n  <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\" ng-show=\\\"$index==current\\\">\\n  <pre class=\\\"cm-s-neo\\\" data-mode=\\\"java\\\">\\n  <span class=\\\"cm-keyword\\\">class</span> <span class=\\\"cm-def\\\">Callback</span> <span class=\\\"cm-keyword\\\">extends</span> <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> {\\n    <span class=\\\"cm-keyword\\\">public</span> <span class=\\\"cm-variable-3\\\">String</span> <span class=\\\"cm-variable\\\">getState</span>() {\\n      <span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">getRequestHandler</span>().<span class=\\\"cm-variable\\\">getParam</span>(<span class=\\\"cm-variable\\\">PARAMETER_STATE</span>);\\n    }\\n    <span class=\\\"cm-keyword\\\">public</span> <span class=\\\"cm-variable-3\\\">String</span> <span class=\\\"cm-variable\\\">getAccessToken</span>() {\\n      <span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">getRequestHandler</span>().<span class=\\\"cm-variable\\\">getParam</span>(<span class=\\\"cm-variable\\\">PARAMETER_ACCESS_TOKEN</span>);\\n    }\\n    <span class=\\\"cm-keyword\\\">protected</span> <span class=\\\"cm-variable-3\\\">void</span> <span class=\\\"cm-variable\\\">handleCancel</span>() {\\n      <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">sendHeader</span>(<span class=\\\"cm-string\\\">\\\"Location\\\"</span>, <span class=\\\"cm-string\\\">\\\"/login\\\"</span>);\\n    }\\n    <span class=\\\"cm-keyword\\\">protected</span> <span class=\\\"cm-variable-3\\\">void</span> <span class=\\\"cm-variable\\\">handleError</span>() {\\n      <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">sendHeader</span>(<span class=\\\"cm-string\\\">\\\"Location\\\"</span>, <span class=\\\"cm-string\\\">\\\"/login?msg=rublon-error\\\"</span>);\\n    }\\n    <span class=\\\"cm-keyword\\\">protected</span> <span class=\\\"cm-variable-3\\\">void</span> <span class=\\\"cm-variable\\\">userAuthenticated</span>(<span class=\\\"cm-variable-3\\\">String</span> <span class=\\\"cm-variable\\\">userId</span>) {\\n      <span class=\\\"cm-variable\\\">Session</span>.<span class=\\\"cm-variable\\\">setUser</span>(<span class=\\\"cm-variable\\\">User</span>.<span class=\\\"cm-variable\\\">getById</span>(<span class=\\\"cm-variable\\\">userId</span>));\\n      <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">sendHeader</span>(<span class=\\\"cm-string\\\">\\\"Location\\\"</span>, <span class=\\\"cm-string\\\">\\\"/dashboard\\\"</span>);\\n    }\\n  }\\n  \\n  ...\\n\\n  <span class=\\\"cm-variable\\\">Rublon2Factor</span> <span class=\\\"cm-variable\\\">rublon</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">new</span> <span class=\\\"cm-variable\\\">Rublon2Factor</span>(\\n    <span class=\\\"cm-string\\\">\\\"A69FC450848B4B94A040416DC4421523\\\"</span>,\\n    <span class=\\\"cm-string\\\">\\\"bLS6NDP7pGjg346S4IHqTHgQQjjSLw3CyApvz5iRjYzgIPN4e9EOi1cQJLrTlvLoHY8zeqg4ILrItYidKJ6JjEUZaA6pR1tZMwSZ\\\"</span>\\n  );\\n    \\n  <span class=\\\"cm-keyword\\\">try</span> {\\n  \\n    <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span> <span class=\\\"cm-variable\\\">callback</span> <span class=\\\"cm-operator\\\">=</span> <span class=\\\"cm-keyword\\\">new</span> <span class=\\\"cm-variable\\\">Rublon2FactorCallback</span>(<span class=\\\"cm-variable\\\">rublon</span>);\\n    <span class=\\\"cm-variable\\\">callback</span>.<span class=\\\"cm-variable\\\">call</span>();\\n    \\n  } <span class=\\\"cm-keyword\\\">catch</span> (<span class=\\\"cm-variable\\\">CallbackException</span> <span class=\\\"cm-variable\\\">e</span>) {\\n    <span class=\\\"cm-comment\\\">// Please handle this error in the better way:</span>\\n    <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">setStatus</span>(<span class=\\\"cm-number\\\">500</span>);\\n    <span class=\\\"cm-variable\\\">HttpServer</span>.<span class=\\\"cm-variable\\\">setResponse</span>(<span class=\\\"cm-string\\\">\\\"There was an error, please try again later. \\\"</span> <span class=\\\"cm-operator\\\">+</span> <span class=\\\"cm-variable\\\">e</span>.<span class=\\\"cm-variable\\\">getMessage</span>());\\n  }</pre>\\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html --> \\n    </div>\\n    <div role=\\\"tabpanel\\\" class=\\\"tab-pane\\\" id=\\\"python2\\\">\\n      <br/>\\n<p>As a prerequisite we need to subclass <code>Rublon2FactorCallback</code> as getting query and post params is not cross-framework in Python and therefore it might need adaptation, there are three abstract methods to override: </p>\\n <!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\\\"ng-scope\\\" ng-switch-when=\\\"code\\\"><div type=\\\"section.type\\\" ng-model=\\\"section.data\\\" class=\\\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\\\">\\n  <div class=\\\"code-tabs ng-hide\\\" ng-show=\\\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\\\">\\n    <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope tab on\\\" ng-class=\\\"{tab: true, on:$index==current, off:$index!=current}\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\">\\n      <a href=\\\"\\\" ng-click=\\\"choose($index)\\\">\\n        <!-- ngIf: tab.status -->\\n        <!-- ngIf: !tab.status --><span class=\\\"ng-scope ng-binding\\\" ng-if=\\\"!tab.status\\\">\\n          Python\\n        </span><!-- end ngIf: !tab.status -->\\n      </a><span class=\\\"ng-hide\\\" ng-hide=\\\"$last\\\">·</span>\\n    </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n  </div>\\n\\n  <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\" ng-show=\\\"$index==current\\\">\\n  <pre class=\\\"cm-s-neo\\\" data-mode=\\\"python\\\"><span class=\\\"cm-keyword\\\">class</span> <span class=\\\"cm-def\\\">Rublon2FactorCallbackFlask</span>(<span class=\\\"cm-variable\\\">Rublon2FactorCallback</span>):\\n    <span class=\\\"cm-keyword\\\">def</span> <span class=\\\"cm-def\\\">get_raw_request_body</span>(<span class=\\\"cm-variable-2\\\">self</span>):\\n        <span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">request</span>.<span class=\\\"cm-variable\\\">get_data</span>()\\n\\n    <span class=\\\"cm-keyword\\\">def</span> <span class=\\\"cm-def\\\">get_state</span>(<span class=\\\"cm-variable-2\\\">self</span>):\\n        <span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">request</span>.<span class=\\\"cm-variable\\\">args</span>.<span class=\\\"cm-variable\\\">get</span>(<span class=\\\"cm-variable-2\\\">self</span>.<span class=\\\"cm-variable\\\">PARAMETER_STATE</span>)\\n\\n    <span class=\\\"cm-keyword\\\">def</span> <span class=\\\"cm-def\\\">get_access_token</span>(<span class=\\\"cm-variable-2\\\">self</span>):\\n        <span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">request</span>.<span class=\\\"cm-variable\\\">args</span>.<span class=\\\"cm-variable\\\">get</span>(<span class=\\\"cm-variable-2\\\">self</span>.<span class=\\\"cm-variable\\\">PARAMETER_ACCESS_TOKEN</span>)</pre>\\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html -->\\n<p> As you can see it's fairly simple in Flask. </p>\\n  <div type=\\\"section.type\\\" ng-model=\\\"section.data\\\" class=\\\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\\\">\\n  <div class=\\\"code-tabs ng-hide\\\" ng-show=\\\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\\\">\\n    <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope tab on\\\" ng-class=\\\"{tab: true, on:$index==current, off:$index!=current}\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\">\\n      <a href=\\\"\\\" ng-click=\\\"choose($index)\\\">\\n        <!-- ngIf: tab.status -->\\n        <!-- ngIf: !tab.status --><span class=\\\"ng-scope ng-binding\\\" ng-if=\\\"!tab.status\\\">\\n          Python\\n        </span><!-- end ngIf: !tab.status -->\\n      </a><span class=\\\"ng-hide\\\" ng-hide=\\\"$last\\\">·</span>\\n    </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n  </div>\\n\\n  <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\\\"ng-scope\\\" ng-repeat=\\\"tab in data.codes track by $id($index)\\\" ng-show=\\\"$index==current\\\">\\n  <pre class=\\\"cm-s-neo\\\" data-mode=\\\"python\\\"><span class=\\\"cm-variable\\\">rublon</span> = <span class=\\\"cm-variable\\\">Rublon2Factor</span>(<span class=\\\"cm-variable\\\">RUBLON_SYSTEM_TOKEN</span>, <span class=\\\"cm-variable\\\">RUBLON_SECRET_KEY</span>)\\n<span class=\\\"cm-variable\\\">callback</span> = <span class=\\\"cm-variable\\\">Rublon2FactorCallbackFlask</span>(<span class=\\\"cm-variable\\\">rublon</span>)\\n<span class=\\\"cm-variable\\\">callback</span>.<span class=\\\"cm-variable\\\">call</span>(<span class=\\\"cm-variable\\\">success_handler</span>=<span class=\\\"cm-variable\\\">rublon_user_logged_in_callback</span>,\\n              <span class=\\\"cm-variable\\\">cancel_handler</span>=<span class=\\\"cm-variable\\\">rublon_cancel_callback</span>)\\n<span class=\\\"cm-keyword\\\">return</span> <span class=\\\"cm-variable\\\">redirect</span>(<span class=\\\"cm-variable\\\">request</span>.<span class=\\\"cm-variable\\\">url_root</span>) <span class=\\\"cm-operator\\\">//</span><span class=\\\"cm-number\\\">2</span>\\n\\n<span class=\\\"cm-keyword\\\">def</span> <span class=\\\"cm-def\\\">rublon_user_logged_in_callback</span>(<span class=\\\"cm-variable\\\">user_id</span>, <span class=\\\"cm-variable\\\">callback</span>):\\n    <span class=\\\"cm-variable\\\">session</span>[<span class=\\\"cm-string\\\">'user_id'</span>] = <span class=\\\"cm-variable\\\">user_id</span> <span class=\\\"cm-operator\\\">//</span><span class=\\\"cm-number\\\">1</span>\\n\\n<span class=\\\"cm-keyword\\\">def</span> <span class=\\\"cm-def\\\">rublon_cancel_callback</span>(<span class=\\\"cm-variable\\\">callback</span>):\\n    <span class=\\\"cm-keyword\\\">raise</span> <span class=\\\"cm-variable\\\">Exception</span>(<span class=\\\"cm-string\\\">'Request cancelled'</span>)</pre>\\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\\n</div>\\n  <ol>\\n    <li>This piece of code is to finalize our auth process. We are using the user's email instead a numeric ID</li>\\n    <li>If everything is ok, redirect to the secured area (main page in this case)</li>\\n\\n  </ol>\\n  \\n    </div>\\n  </div>\\n\\n</div>\\n<style>\\n.langnav > li > a {\\n    padding: 3px 15px;\\n}\\ncaption{\\nmargin:10px;\\n}\\n  .tab-pane h3 {\\n    color: #555;\\n    font-size: 17px;\\n    font-weight: 700;\\n    text-transform: uppercase;\\n}\\n</style>\"\n}\n[/block]","excerpt":"","slug":"sdk-authentication-finalization","type":"basic","title":"Authentication finalization"}

Authentication finalization


After a successful authentication Rublon will redirect the user's browser to the callback URL. The callback flow continues the authentication process, i.e. the finalization of the authentication (logging in or identity confirmation). ## Input params The callback URL will receive its input arguments in the URL address itself (*query string*). [block:html] { "html": "<div>\n\n <!-- Nav tabs -->\n <ul class=\"nav nav-tabs langnav\" role=\"tablist\">\n <li role=\"presentation\" class=\"active\"><a href=\"#php\" aria-controls=\"php\" role=\"tab\" data-toggle=\"tab\">PHP</a></li>\n <li role=\"presentation\"><a href=\"#net\" aria-controls=\"net\" role=\"tab\" data-toggle=\"tab\">.NET</a></li>\n <li role=\"presentation\"><a href=\"#java\" aria-controls=\"java\" role=\"tab\" data-toggle=\"tab\">Java</a></li>\n <li role=\"presentation\"><a href=\"#python\" aria-controls=\"python\" role=\"tab\" data-toggle=\"tab\">Python</a></li>\n </ul>\n\n <!-- Tab panes -->\n <div class=\"tab-content\">\n <div role=\"tabpanel\" class=\"tab-pane active\" id=\"php\">\n<table>\n\t<caption>Callback URL arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>state</code></td><td>string</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\n\t\t<tr><td><code>token</code></td><td>string</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\n\t</tbody>\n</table> \n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"net\">\n<table>\n\t<caption>Callback URL arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>state</code></td><td>string</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\n\t\t<tr><td><code>token</code></td><td>string</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\n\t</tbody>\n</table> \n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"java\">\n<table>\n\t<caption>Callback URL arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>state</code></td><td>String</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\n\t\t<tr><td><code>token</code></td><td>String</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\n\t</tbody>\n</table>\n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"python\">\n<table>\n\t<caption>Callback URL arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>state</code></td><td>str</td><td>Authentication result: <code>ok</code>, <code>error</code> or <code>cancel</code></td></tr>\n\t\t<tr><td><code>token</code></td><td>str</td><td>Access token (100 alphanumeric characters, upper- and lowercase), which allows authentication's verification using a background Rublon API connection</td></tr>\n\t</tbody>\n</table>\n </div>\n </div>\n\n</div>\n<style>\n.langnav > li > a {\n padding: 3px 15px;\n}\ncaption{\nmargin:10px;\n}\n</style>" } [/block] [block:callout] { "type": "info", "body": "Notice: If the callback URL has been set to e.g. `http://example.com/twofactor/auth/`, the params will be appended to the URL address: \n\n<pre>`http://example.com/twofactor/auth/?state=ok&token=Kmad4hAS...d`</pre>\n\nIf your callback URL should be formed differently (e.g. when using mod_rewrite), you can set the callback URL's template using the meta-tags: `%token%` and `%state%`, like so:\n\n<pre>`http://example.com/twofactor/auth/%state%/%token%`</pre>" } [/block] ## Authentication verification [block:html] { "html": "<div>\n\n <!-- Nav tabs -->\n <ul class=\"nav nav-tabs langnav\" role=\"tablist\">\n <li role=\"presentation\" class=\"active\"><a href=\"#php2\" aria-controls=\"php\" role=\"tab\" data-toggle=\"tab\">PHP</a></li>\n <li role=\"presentation\"><a href=\"#net2\" aria-controls=\"net\" role=\"tab\" data-toggle=\"tab\">.NET</a></li>\n <li role=\"presentation\"><a href=\"#java2\" aria-controls=\"java\" role=\"tab\" data-toggle=\"tab\">Java</a></li>\n <li role=\"presentation\"><a href=\"#python2\" aria-controls=\"python\" role=\"tab\" data-toggle=\"tab\">Python</a></li>\n </ul>\n\n <!-- Tab panes -->\n <div class=\"tab-content\">\n <div role=\"tabpanel\" class=\"tab-pane active\" id=\"php2\">\n <br/>\n <p>After the callback is invoked, for proper finalization of the authentication process you need to instantiate a <code>Rublon2FactorCallback</code> class object.</p>\n <table>\n\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>$rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\n\t</tbody>\n</table> \n <p>Next, the <code>Rublon2FactorCallback::call()</code> method should be called. It takes two arguments.</p>\n\n<table>\n\t<caption><code>Rublon2FactorCallback::call</code> method arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>$successHandler</code></td><td>callable</td><td>Name of a function/method, or an anonymous function/closure, which will be invoked on successful verification of the process, finalizing the authentication (logging the user in or confirming the user's identity for some operation).</td></tr>\n\t\t<tr><td><code>$cancelHandler</code></td><td>callable</td><td>Name of a function/method, or an anonymous function/closure, which will be invoked on receiving the <code>cancel</code> state to cancel the authentication transaction.</td></tr>\n\t</tbody>\n</table>\n\n<table>\n\t<caption>Arguments of the <code>$successHandler</code> function, passed to the <code>Rublon2FactorCallback::call</code> method</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>$userId</code></td><td>string</td><td>The user's unique Id in the integrated system, given as an argument to the <code>Rublon2Factor::auth</code> method, whose authentication is being confirmed by Rublon\n</td></tr>\n\t\t<tr><td><code>$callback</code></td><td>Rublon2FactorCallback</td><td>An instance of the <code>Rublon2FactorCallback</code> class</td></tr>\n\t</tbody>\n</table>\n \n<table>\n\t<caption>Argument of the <code>$cancelHandler</code> function, passed to the <code>Rublon2FactorCallback::call</code> method</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>$callback</code></td><td>Rublon2FactorCallback</td><td>An instance of the <code>Rublon2FactorCallback</code> class</td></tr>\n\t</tbody>\n</table> \n <h3>Example PHP code</h3>\n<p>An example of the <code>Rublon2FactorCallback</code> class usage in the callback:</p>\n<!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\"ng-scope\" ng-switch-when=\"code\"><div type=\"section.type\" ng-model=\"section.data\" class=\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\">\n <div class=\"code-tabs ng-hide\" ng-show=\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\">\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope tab on\" ng-class=\"{tab: true, on:$index==current, off:$index!=current}\" ng-repeat=\"tab in data.codes track by $id($index)\">\n <a href=\"\" ng-click=\"choose($index)\">\n <!-- ngIf: tab.status -->\n <!-- ngIf: !tab.status --><span class=\"ng-scope ng-binding\" ng-if=\"!tab.status\">\n PHP\n </span><!-- end ngIf: !tab.status -->\n </a><span class=\"ng-hide\" ng-hide=\"$last\">·</span>\n </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n </div>\n\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope\" ng-repeat=\"tab in data.codes track by $id($index)\" ng-show=\"$index==current\">\n <pre class=\"cm-s-neo\" data-mode=\"php\"><span class=\"cm-meta\">&lt;?</span>\n<span class=\"cm-variable-2\">$rublon</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">new</span> <span class=\"cm-variable\">Rublon2Factor</span>(<span class=\"cm-string\">\"</span><span class=\"cm-string\">your_system_token\"</span>, <span class=\"cm-string\">\"</span><span class=\"cm-string\">your_access_key\"</span>);\n\n<span class=\"cm-keyword\">try</span> {\n <span class=\"cm-variable-2\">$callback</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">new</span> <span class=\"cm-variable\">Rublon2FactorCallback</span>(<span class=\"cm-variable-2\">$rublon</span>);\n <span class=\"cm-variable-2\">$callback</span><span class=\"cm-operator\">-&gt;</span><span class=\"cm-variable\">call</span>(\n <span class=\"cm-variable-2\">$successHandler</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">function</span>(<span class=\"cm-variable-2\">$userId</span>, <span class=\"cm-variable\">Rublon2FactorCallback</span> <span class=\"cm-variable-2\">$callback</span>) {\n <span class=\"cm-comment\">// The user is finally logged in</span>\n <span class=\"cm-variable-2\">$_SESSION</span>[<span class=\"cm-string\">\"</span><span class=\"cm-string\">user\"</span>] <span class=\"cm-operator\">=</span> <span class=\"cm-variable-2\">$userId</span>;\n },\n <span class=\"cm-variable-2\">$cancelHandler</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">function</span>(<span class=\"cm-variable\">Rublon2FactorCallback</span> <span class=\"cm-variable-2\">$callback</span>) {\n <span class=\"cm-comment\">// Cancel the authentication process</span>\n <span class=\"cm-builtin\">header</span>(<span class=\"cm-string\">\"</span><span class=\"cm-string\">Location: /login\"</span>);\n <span class=\"cm-keyword\">exit</span>;\n }\n );\n \n <span class=\"cm-comment\">// The authentication process was successful</span>\n <span class=\"cm-builtin\">header</span>(<span class=\"cm-string\">\"</span><span class=\"cm-string\">Location: /dashboard\"</span>);\n <span class=\"cm-keyword\">exit</span>;\n\n} <span class=\"cm-keyword\">catch</span> (<span class=\"cm-variable\">RublonException</span> <span class=\"cm-variable-2\">$e</span>) {\n <span class=\"cm-comment\">// Please handle this error in the better way:</span>\n <span class=\"cm-keyword\">die</span>(<span class=\"cm-variable-2\">$e</span><span class=\"cm-operator\">-&gt;</span><span class=\"cm-variable\">getMessage</span>());\n}</pre>\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html --> \n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"net2\">\n <br/>\n <p>After the callback is invoked, for proper finalization of the authentication process you need to create a <code>Rublon2FactorCallback</code> subclass instance. Because the <code>Rublon2FactorCallback</code> class in abstract you need to create a subclass that implement needed methods which depend on your system details.</p>\n <table>\n\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\n\t</tbody>\n</table> \n \n <p>Next, the <code>Rublon2FactorCallback.Call()</code> method should be called.</p>\n<p>The following abstract methods should be implemented in a subclass.</p>\n<ul>\n <li><code>string getState()</code> - returns the \"state\" parameter from the HTTP GET request.</li>\n\t<li><code>string getAccessToken()</code> - returns the \"token\" parameter from the HTTP GET request.</li>\n<li><code>void handleCancel()</code> - called when the state parameter is not \"ok\" nor \"error\".</li>\n<li><code>void handleError()</code> - called when the state parameter value is \"error\".</li>\n<li><code>void userAuthenticated(string userId)</code> - handle the authenticated user with given user's local ID.</li>\n</ul>\n<h3>Example .NET code </h3> \n<p>An example implementation of the <code>Rublon2FactorCallback</code> class and usage in the callback:</p>\n <!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\"ng-scope\" ng-switch-when=\"code\"><div type=\"section.type\" ng-model=\"section.data\" class=\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\">\n <div class=\"code-tabs ng-hide\" ng-show=\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\">\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope tab on\" ng-class=\"{tab: true, on:$index==current, off:$index!=current}\" ng-repeat=\"tab in data.codes track by $id($index)\">\n <a href=\"\" ng-click=\"choose($index)\">\n <!-- ngIf: tab.status -->\n <!-- ngIf: !tab.status --><span class=\"ng-scope ng-binding\" ng-if=\"!tab.status\">\n C#\n </span><!-- end ngIf: !tab.status -->\n </a><span class=\"ng-hide\" ng-hide=\"$last\">·</span>\n </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n </div>\n\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope\" ng-repeat=\"tab in data.codes track by $id($index)\" ng-show=\"$index==current\">\n <pre class=\"cm-s-neo\" data-mode=\"csharp\"><span class=\"cm-variable\">class</span> <span class=\"cm-variable\">Callback</span> : <span class=\"cm-variable\">Rublon2FactorCallback</span> \n{\n <span class=\"cm-variable\">protected</span> <span class=\"cm-variable\">override</span> <span class=\"cm-variable\">string</span> <span class=\"cm-variable\">getState</span>() \n {\n <span class=\"cm-variable\">return</span> <span class=\"cm-variable\">Request</span>.<span class=\"cm-variable\">Params</span>[<span class=\"cm-variable\">PARAMETER_STATE</span>];\n }\n \n <span class=\"cm-variable\">protected</span> <span class=\"cm-variable\">override</span> <span class=\"cm-variable\">string</span> <span class=\"cm-variable\">getAccessToken</span>() \n {\n <span class=\"cm-variable\">return</span> <span class=\"cm-variable\">Request</span>.<span class=\"cm-variable\">Params</span>[<span class=\"cm-variable\">PARAMETER_ACCESS_TOKEN</span>];\n }\n \n <span class=\"cm-variable\">protected</span> <span class=\"cm-variable\">override</span> <span class=\"cm-variable\">void</span> <span class=\"cm-variable\">handleCancel</span>() \n {\n <span class=\"cm-variable\">Response</span>.<span class=\"cm-variable\">Redirect</span>(<span class=\"cm-string\">\"/Login\"</span>);\n }\n \n <span class=\"cm-variable\">protected</span> <span class=\"cm-variable\">override</span> <span class=\"cm-variable\">void</span> <span class=\"cm-variable\">handleError</span>() \n {\n <span class=\"cm-variable\">Response</span>.<span class=\"cm-variable\">Redirect</span>(<span class=\"cm-string\">\"/Login/?msg=rublon-error\"</span>);\n }\n \n <span class=\"cm-variable\">protected</span> <span class=\"cm-variable\">override</span> <span class=\"cm-variable\">void</span> <span class=\"cm-variable\">userAuthenticated</span>(<span class=\"cm-variable\">string</span> <span class=\"cm-variable\">userId</span>) \n {\n <span class=\"cm-variable\">Session</span>[<span class=\"cm-string\">\"loggedUsed\"</span>] <span class=\"cm-operator\">=</span> <span class=\"cm-variable\">User</span>.<span class=\"cm-variable\">GetById</span>(<span class=\"cm-variable\">userId</span>);\n <span class=\"cm-variable\">Response</span>.<span class=\"cm-variable\">Redirect</span>(<span class=\"cm-string\">\"/\"</span>);\n }\n}\n\n...\n\n<span class=\"cm-variable\">Rublon2Factor</span> <span class=\"cm-variable\">rublon</span> <span class=\"cm-operator\">=</span> <span class=\"cm-variable\">new</span> <span class=\"cm-variable\">Rublon2Factor</span>\n(\n <span class=\"cm-string\">\"A69FC450848B4B94A040416DC4421523\"</span>,\n <span class=\"cm-string\">\"bLS6NDP7pGjg346S4IHqTHgQQjjSLw3CyApvz5iRjYzgIPN4e9EOi1cQJLrTlvLoHY8zeqg4ILrItYidKJ6JjEUZaA6pR1tZMwSZ\"</span>\n);\n\n<span class=\"cm-variable\">try</span> \n{\n <span class=\"cm-variable\">Rublon2FactorCallback</span> <span class=\"cm-variable\">callback</span> <span class=\"cm-operator\">=</span> <span class=\"cm-variable\">new</span> <span class=\"cm-variable\">Callback</span>(<span class=\"cm-variable\">rublon</span>);\n <span class=\"cm-variable\">callback</span>.<span class=\"cm-variable\">Call</span>();\n} \n<span class=\"cm-variable\">catch</span> (<span class=\"cm-variable\">CallbackException</span> <span class=\"cm-variable\">ex</span>) \n{\n <span class=\"cm-comment\">// Please handle this error in the better way:</span>\n <span class=\"cm-variable\">throw</span>;\n}</pre>\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html --> \n \n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"java2\">\n <br/>\n <p>After the callback is invoked, for proper finalization of the authentication process you need to create a <code>Rublon2FactorCallback</code> subclass instance. Because the <code>Rublon2FactorCallback</code> class in abstract you need to create a subclass\nthat implement needed methods which depend on your system details.</p>\n <table>\n\t<caption><code>Rublon2FactorCallback</code> class constructor method arguments</caption>\n\t<thead><tr>\n\t\t<th>Name</th>\n\t\t<th>Type</th>\n\t\t<th>Description</th>\n\t</tr></thead>\n\t<tbody>\n\t\t<tr><td><code>rublon</code></td><td>Rublon2Factor</td><td>An instance of the <code>Rublon2Factor</code> class</td></tr>\n\t</tbody>\n</table> \n \n <p>Next, the <code>Rublon2FactorCallback.call()</code> method should be called.</p>\n<p>The following abstract methods should be implemented in a subclass.</p>\n<ul>\n <li><code>String getState()</code> - returns the \"state\" parameter from the HTTP GET request.</li>\n\t<li><code>String getAccessToken()</code> - returns the \"token\" parameter from the HTTP GET request.</li>\n<li><code>void handleCancel()</code> - called when the state parameter is not \"ok\" nor \"error\".</li>\n<li><code>void handleError()</code> - called when the state parameter value is \"error\".</li>\n<li><code>void userAuthenticated(String userId)</code> - handle the authenticated user with given user's local ID.</li>\n</ul>\n<h3>Example JAVA code </h3> \n<p>An example implementation of the <code>Rublon2FactorCallback</code> class and usage in the callback:</p> \n<!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\"ng-scope\" ng-switch-when=\"code\"><div type=\"section.type\" ng-model=\"section.data\" class=\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\">\n <div class=\"code-tabs ng-hide\" ng-show=\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\">\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope tab on\" ng-class=\"{tab: true, on:$index==current, off:$index!=current}\" ng-repeat=\"tab in data.codes track by $id($index)\">\n <a href=\"\" ng-click=\"choose($index)\">\n <!-- ngIf: tab.status -->\n <!-- ngIf: !tab.status --><span class=\"ng-scope ng-binding\" ng-if=\"!tab.status\">\n Java\n </span><!-- end ngIf: !tab.status -->\n </a><span class=\"ng-hide\" ng-hide=\"$last\">·</span>\n </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n </div>\n\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope\" ng-repeat=\"tab in data.codes track by $id($index)\" ng-show=\"$index==current\">\n <pre class=\"cm-s-neo\" data-mode=\"java\">\n <span class=\"cm-keyword\">class</span> <span class=\"cm-def\">Callback</span> <span class=\"cm-keyword\">extends</span> <span class=\"cm-variable\">Rublon2FactorCallback</span> {\n <span class=\"cm-keyword\">public</span> <span class=\"cm-variable-3\">String</span> <span class=\"cm-variable\">getState</span>() {\n <span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">getRequestHandler</span>().<span class=\"cm-variable\">getParam</span>(<span class=\"cm-variable\">PARAMETER_STATE</span>);\n }\n <span class=\"cm-keyword\">public</span> <span class=\"cm-variable-3\">String</span> <span class=\"cm-variable\">getAccessToken</span>() {\n <span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">getRequestHandler</span>().<span class=\"cm-variable\">getParam</span>(<span class=\"cm-variable\">PARAMETER_ACCESS_TOKEN</span>);\n }\n <span class=\"cm-keyword\">protected</span> <span class=\"cm-variable-3\">void</span> <span class=\"cm-variable\">handleCancel</span>() {\n <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">sendHeader</span>(<span class=\"cm-string\">\"Location\"</span>, <span class=\"cm-string\">\"/login\"</span>);\n }\n <span class=\"cm-keyword\">protected</span> <span class=\"cm-variable-3\">void</span> <span class=\"cm-variable\">handleError</span>() {\n <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">sendHeader</span>(<span class=\"cm-string\">\"Location\"</span>, <span class=\"cm-string\">\"/login?msg=rublon-error\"</span>);\n }\n <span class=\"cm-keyword\">protected</span> <span class=\"cm-variable-3\">void</span> <span class=\"cm-variable\">userAuthenticated</span>(<span class=\"cm-variable-3\">String</span> <span class=\"cm-variable\">userId</span>) {\n <span class=\"cm-variable\">Session</span>.<span class=\"cm-variable\">setUser</span>(<span class=\"cm-variable\">User</span>.<span class=\"cm-variable\">getById</span>(<span class=\"cm-variable\">userId</span>));\n <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">sendHeader</span>(<span class=\"cm-string\">\"Location\"</span>, <span class=\"cm-string\">\"/dashboard\"</span>);\n }\n }\n \n ...\n\n <span class=\"cm-variable\">Rublon2Factor</span> <span class=\"cm-variable\">rublon</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">new</span> <span class=\"cm-variable\">Rublon2Factor</span>(\n <span class=\"cm-string\">\"A69FC450848B4B94A040416DC4421523\"</span>,\n <span class=\"cm-string\">\"bLS6NDP7pGjg346S4IHqTHgQQjjSLw3CyApvz5iRjYzgIPN4e9EOi1cQJLrTlvLoHY8zeqg4ILrItYidKJ6JjEUZaA6pR1tZMwSZ\"</span>\n );\n \n <span class=\"cm-keyword\">try</span> {\n \n <span class=\"cm-variable\">Rublon2FactorCallback</span> <span class=\"cm-variable\">callback</span> <span class=\"cm-operator\">=</span> <span class=\"cm-keyword\">new</span> <span class=\"cm-variable\">Rublon2FactorCallback</span>(<span class=\"cm-variable\">rublon</span>);\n <span class=\"cm-variable\">callback</span>.<span class=\"cm-variable\">call</span>();\n \n } <span class=\"cm-keyword\">catch</span> (<span class=\"cm-variable\">CallbackException</span> <span class=\"cm-variable\">e</span>) {\n <span class=\"cm-comment\">// Please handle this error in the better way:</span>\n <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">setStatus</span>(<span class=\"cm-number\">500</span>);\n <span class=\"cm-variable\">HttpServer</span>.<span class=\"cm-variable\">setResponse</span>(<span class=\"cm-string\">\"There was an error, please try again later. \"</span> <span class=\"cm-operator\">+</span> <span class=\"cm-variable\">e</span>.<span class=\"cm-variable\">getMessage</span>());\n }</pre>\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html --> \n </div>\n <div role=\"tabpanel\" class=\"tab-pane\" id=\"python2\">\n <br/>\n<p>As a prerequisite we need to subclass <code>Rublon2FactorCallback</code> as getting query and post params is not cross-framework in Python and therefore it might need adaptation, there are three abstract methods to override: </p>\n <!-- ngSwitchWhen: textarea --><!-- TODO: Make this generic using 'default' --><!-- ngSwitchWhen: api-header --><!-- ngSwitchWhen: code --><div class=\"ng-scope\" ng-switch-when=\"code\"><div type=\"section.type\" ng-model=\"section.data\" class=\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\">\n <div class=\"code-tabs ng-hide\" ng-show=\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\">\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope tab on\" ng-class=\"{tab: true, on:$index==current, off:$index!=current}\" ng-repeat=\"tab in data.codes track by $id($index)\">\n <a href=\"\" ng-click=\"choose($index)\">\n <!-- ngIf: tab.status -->\n <!-- ngIf: !tab.status --><span class=\"ng-scope ng-binding\" ng-if=\"!tab.status\">\n Python\n </span><!-- end ngIf: !tab.status -->\n </a><span class=\"ng-hide\" ng-hide=\"$last\">·</span>\n </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n </div>\n\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope\" ng-repeat=\"tab in data.codes track by $id($index)\" ng-show=\"$index==current\">\n <pre class=\"cm-s-neo\" data-mode=\"python\"><span class=\"cm-keyword\">class</span> <span class=\"cm-def\">Rublon2FactorCallbackFlask</span>(<span class=\"cm-variable\">Rublon2FactorCallback</span>):\n <span class=\"cm-keyword\">def</span> <span class=\"cm-def\">get_raw_request_body</span>(<span class=\"cm-variable-2\">self</span>):\n <span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">request</span>.<span class=\"cm-variable\">get_data</span>()\n\n <span class=\"cm-keyword\">def</span> <span class=\"cm-def\">get_state</span>(<span class=\"cm-variable-2\">self</span>):\n <span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">request</span>.<span class=\"cm-variable\">args</span>.<span class=\"cm-variable\">get</span>(<span class=\"cm-variable-2\">self</span>.<span class=\"cm-variable\">PARAMETER_STATE</span>)\n\n <span class=\"cm-keyword\">def</span> <span class=\"cm-def\">get_access_token</span>(<span class=\"cm-variable-2\">self</span>):\n <span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">request</span>.<span class=\"cm-variable\">args</span>.<span class=\"cm-variable\">get</span>(<span class=\"cm-variable-2\">self</span>.<span class=\"cm-variable\">PARAMETER_ACCESS_TOKEN</span>)</pre>\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n</div></div><!-- ngSwitchWhen: image --><!-- ngSwitchWhen: embed --><!-- ngSwitchWhen: callout --><!-- ngSwitchWhen: parameters --><!-- ngSwitchWhen: html -->\n<p> As you can see it's fairly simple in Flask. </p>\n <div type=\"section.type\" ng-model=\"section.data\" class=\"block-code block-show-code ng-isolate-scope ng-pristine ng-valid\">\n <div class=\"code-tabs ng-hide\" ng-show=\"data.codes.length > 1 || (data.codes.length == 1 &amp;&amp; data.codes[0].status)\">\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope tab on\" ng-class=\"{tab: true, on:$index==current, off:$index!=current}\" ng-repeat=\"tab in data.codes track by $id($index)\">\n <a href=\"\" ng-click=\"choose($index)\">\n <!-- ngIf: tab.status -->\n <!-- ngIf: !tab.status --><span class=\"ng-scope ng-binding\" ng-if=\"!tab.status\">\n Python\n </span><!-- end ngIf: !tab.status -->\n </a><span class=\"ng-hide\" ng-hide=\"$last\">·</span>\n </div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n </div>\n\n <!-- ngRepeat: tab in data.codes track by $id($index) --><div class=\"ng-scope\" ng-repeat=\"tab in data.codes track by $id($index)\" ng-show=\"$index==current\">\n <pre class=\"cm-s-neo\" data-mode=\"python\"><span class=\"cm-variable\">rublon</span> = <span class=\"cm-variable\">Rublon2Factor</span>(<span class=\"cm-variable\">RUBLON_SYSTEM_TOKEN</span>, <span class=\"cm-variable\">RUBLON_SECRET_KEY</span>)\n<span class=\"cm-variable\">callback</span> = <span class=\"cm-variable\">Rublon2FactorCallbackFlask</span>(<span class=\"cm-variable\">rublon</span>)\n<span class=\"cm-variable\">callback</span>.<span class=\"cm-variable\">call</span>(<span class=\"cm-variable\">success_handler</span>=<span class=\"cm-variable\">rublon_user_logged_in_callback</span>,\n <span class=\"cm-variable\">cancel_handler</span>=<span class=\"cm-variable\">rublon_cancel_callback</span>)\n<span class=\"cm-keyword\">return</span> <span class=\"cm-variable\">redirect</span>(<span class=\"cm-variable\">request</span>.<span class=\"cm-variable\">url_root</span>) <span class=\"cm-operator\">//</span><span class=\"cm-number\">2</span>\n\n<span class=\"cm-keyword\">def</span> <span class=\"cm-def\">rublon_user_logged_in_callback</span>(<span class=\"cm-variable\">user_id</span>, <span class=\"cm-variable\">callback</span>):\n <span class=\"cm-variable\">session</span>[<span class=\"cm-string\">'user_id'</span>] = <span class=\"cm-variable\">user_id</span> <span class=\"cm-operator\">//</span><span class=\"cm-number\">1</span>\n\n<span class=\"cm-keyword\">def</span> <span class=\"cm-def\">rublon_cancel_callback</span>(<span class=\"cm-variable\">callback</span>):\n <span class=\"cm-keyword\">raise</span> <span class=\"cm-variable\">Exception</span>(<span class=\"cm-string\">'Request cancelled'</span>)</pre>\n</div><!-- end ngRepeat: tab in data.codes track by $id($index) -->\n</div>\n <ol>\n <li>This piece of code is to finalize our auth process. We are using the user's email instead a numeric ID</li>\n <li>If everything is ok, redirect to the secured area (main page in this case)</li>\n\n </ol>\n \n </div>\n </div>\n\n</div>\n<style>\n.langnav > li > a {\n padding: 3px 15px;\n}\ncaption{\nmargin:10px;\n}\n .tab-pane h3 {\n color: #555;\n font-size: 17px;\n font-weight: 700;\n text-transform: uppercase;\n}\n</style>" } [/block]