Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
feat(email-first): Add support for the email-first flow. (#540); r=ph…
Browse files Browse the repository at this point in the history
…ilbooth,rfk

Use the `action=email` query parameter to trigger the
email-first flow. Redirects to `/` on the content
server, propagating the `action=email` query parameter.

fixes #539
  • Loading branch information
Shane Tomlinson authored and rfk committed Apr 10, 2018
1 parent c22f51c commit cb11145
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 11 deletions.
12 changes: 9 additions & 3 deletions docs/api.md
Expand Up @@ -287,9 +287,15 @@ content-server page.
- `redirect_uri`: Optional. If supplied, a string URL of where to redirect afterwards. Must match URL from registration.
- `scope`: Optional. A space-separated list of scopes that the user has authorized. This could be pruned by the user at the confirmation dialog. If this includes the scope `openid`, this will be an OpenID Connect authentication request.
- `access_type`: Optional. If provided, should be `online` or `offline`. `offline` will result in a refresh_token being provided, so that the access_token can be refreshed after it expires.
- `action`: Optional. If provided, should be `signup`, `signin`, or `force_auth`. Send to improve the user experience, based on whether they clicked on a Sign In or Sign Up button. `force_auth` requires the user to sign in using the address specified in `email`. If unspecified then Firefox Accounts will try choose intelligently between `signin` and `signup` based on the user's browser state.
- `email`: Optional if `action` is `signup` or `signin`. Required if `action`
- `action`: Optional. If provided, should be `email`, `signup`, `signin`, or `force_auth`. Send to improve the user experience.
- If unspecified then Firefox Accounts will try choose intelligently between `signin` and `signup` based on the user's browser state.
- `email` triggers the email-first flow, which uses the email address to determine whether to display signup or signin.
- `signin` triggers the signin flow.
- `signup` triggers the signup flow.
- `force_auth` requires the user to sign in using the address specified in `email`.
- `email`: Optional if `action` is `email`, `signup` or `signin`. Required if `action`
is `force_auth`.
- if `action` is `email`, the email address will be used to determine whether to display the signup or signin form, but the user is free to change it.
- If `action` is `signup` or `signin`, the email address will be pre-filled into the account form, but the user is free to change it.
- If `action` is `signin`, the literal string `blank` will force the user to enter an email address and the last signed in email address will be ignored.
- If `action` is `signin` and no email address is specified, the last
Expand Down Expand Up @@ -380,7 +386,7 @@ particular user.
- `code`: A string that was received from the [authorization][] endpoint.
- If `refresh_token`:
- `client_id`: The id returned from client registration.
- `client_secret`: The secret returned from client registration.
- `client_secret`: The secret returned from client registration.
This must not be set if the client is a public (PKCE) client.
- `refresh_token`: A string that received from the [token][]
endpoint specifically as a refresh token.
Expand Down
27 changes: 19 additions & 8 deletions lib/routes/redirect.js
Expand Up @@ -7,17 +7,22 @@ const url = require('url');
const config = require('../config');
const AppError = require('../error');

const ACTION_TO_PATHNAMES = {
'email': '',
'signin': 'signin',
'signup': 'signup',
'force_auth': 'force_auth'
};

function actionToPathname(action) {
if (action === 'signup') {
return 'signup';
} else if (action === 'force_auth') {
return 'force_auth';
} else if (action === 'signin') {
return 'signin';
} else if (action === undefined) {
if (action === undefined) {
return '';
}

if (ACTION_TO_PATHNAMES.hasOwnProperty(action)) {
return ACTION_TO_PATHNAMES[action];
}

throw new Error('Bad action parameter');
}

Expand All @@ -34,7 +39,13 @@ module.exports = {
}

if (! err) {
delete req.query.action;
if (req.query.action !== 'email') {
// only `action=email` is propagated as a hint
// to the content server to show the email-first
// flow. All other actions redirect to a named
// endpoint.
delete req.query.action;
}

if (req.query.login_hint && ! req.query.email) {
req.query.email = req.query.login_hint;
Expand Down
14 changes: 14 additions & 0 deletions test/api.js
Expand Up @@ -292,6 +292,20 @@ describe('/v1', function() {
});
});

it('redirects `action=email` to `/`', function() {
return Server.api.get('/authorization?action=email')
.then(function(res) {
assert.equal(res.statusCode, 302);
assertSecurityHeaders(res);
var redirect = url.parse(res.headers.location, true);

var target = url.parse(config.get('contentUrl'), true);
assert.equal(redirect.pathname, target.pathname);
assert.equal(redirect.host, target.host);
assert.equal(redirect.query.action, 'email');
});
});

it('rewrites `login_hint=foo` to `email=foo`', function() {
var endpoint = '/authorization?action=signin&login_hint=' +
encodeURIComponent(VEMAIL);
Expand Down

0 comments on commit cb11145

Please sign in to comment.