feat(oauth): Add an OAuth-sessionToken exchange endpoint

This commit is contained in:
Edouard Oger 2018-09-17 11:37:50 -04:00
Родитель 11beb47be4
Коммит 17dbac74cd
3 изменённых файлов: 89 добавлений и 0 удалений

Просмотреть файл

@ -24,6 +24,7 @@ see [`mozilla/fxa-js-client`](https://github.com/mozilla/fxa-js-client).
* [Account](#account)
* [POST /account/create](#post-accountcreate)
* [POST /account/login](#post-accountlogin)
* [GET /account/oauth_exchange (:lock: oauthToken)](#get-accountoauth_exchange)
* [GET /account/status (:lock::unlock: sessionToken)](#get-accountstatus)
* [POST /account/status](#post-accountstatus)
* [GET /account/profile (:lock: sessionToken, oauthToken)](#get-accountprofile)
@ -295,6 +296,8 @@ for `code` and `errno` are:
This request requires two step authentication enabled on your account.
* `code: 400, errno: 161`:
Recovery key already exists.
* `code: 401, errno: 162`:
The required scope(s) for this request was not found.
* `code: 503, errno: 201`:
Service unavailable
* `code: 503, errno: 202`:
@ -327,6 +330,7 @@ include additional response properties:
* `errno: 135`: bouncedAt
* `errno: 152`
* `errno: 153`
* `errno: 162`: requiredScopes
* `errno: 201`: retryAfter
* `errno: 202`: retryAfter
* `errno: 203`: service, operation
@ -716,6 +720,23 @@ by the following errors
This request requires two step authentication enabled on your account.
#### GET /account/oauth_exchange
:lock: authenticated with OAuth bearer token
<!--begin-route-get-accountoauth_exchange-->
<!--end-route-get-accountoauth_exchange-->
##### Error responses
Failing requests may be caused
by the following errors
(this is not an exhaustive list):
* `code: 401, errno: 162`:
The required scope(s) for this request was not found.
#### GET /account/status
:lock::unlock: Optionally HAWK-authenticated with session token

Просмотреть файл

@ -75,6 +75,8 @@ var ERRNO = {
TOTP_REQUIRED: 160,
RECOVERY_KEY_EXISTS: 161,
INVALID_SCOPE: 162,
SERVER_BUSY: 201,
FEATURE_NOT_ENABLED: 202,
BACKEND_SERVICE_FAILURE: 203,
@ -851,6 +853,17 @@ AppError.backendServiceFailure = (service, operation) => {
})
}
AppError.invalidScope = (requiredScopes) => {
return new AppError({
code: 401,
error: 'Unauthorized',
errno: ERRNO.INVALID_SCOPE,
message: 'The required scope(s) for this request was not found.'
}, {
requiredScopes
})
}
AppError.unexpectedError = () => {
return new AppError({})
}

Просмотреть файл

@ -22,6 +22,8 @@ const MS_ONE_DAY = MS_ONE_HOUR * 24
const MS_ONE_WEEK = MS_ONE_DAY * 7
const MS_ONE_MONTH = MS_ONE_DAY * 30
const SCOPE_ADMIN = 'https://identity.mozilla.com/admin'
module.exports = (log, db, mailer, Password, config, customs, signinUtils, push) => {
const tokenCodeConfig = config.signinConfirmation.tokenVerificationCode
const tokenCodeLifetime = tokenCodeConfig && tokenCodeConfig.codeLifetime || MS_ONE_HOUR
@ -726,6 +728,59 @@ module.exports = (log, db, mailer, Password, config, customs, signinUtils, push)
}
}
},
{
method: 'GET',
path: '/account/oauth_exchange',
options: {
auth: {
strategy: 'oauthToken',
payload: false, // no payload authentication in OAuth.
},
response: {
schema: {
sessionToken: isA.string().regex(HEX_STRING).required(),
}
}
},
handler: async function (request) {
const auth = request.auth
const uid = auth.credentials.user;
const scope = ScopeSet.fromArray(auth.credentials.scope);
if (! scope.contains(SCOPE_ADMIN)) {
throw error.invalidScope(SCOPE_ADMIN)
}
const account = await db.account(uid);
const {
browser: uaBrowser,
browserVersion: uaBrowserVersion,
os: uaOS,
osVersion: uaOSVersion,
deviceType: uaDeviceType,
formFactor: uaFormFactor
} = request.app.ua
const sessionToken = await db.createSessionToken({
uid: account.uid,
email: account.email,
emailCode: account.emailCode,
emailVerified: account.emailVerified,
verifierSetAt: account.verifierSetAt,
mustVerify: false,
tokenVerificationCode: undefined,
tokenVerificationCodeExpiresAt: undefined,
tokenVerificationId: undefined,
uaBrowser,
uaBrowserVersion,
uaOS,
uaOSVersion,
uaDeviceType,
uaFormFactor
})
return {sessionToken: sessionToken.data}
}
},
{
method: 'GET',
path: '/account/status',