adonis-ally-azure-ad
Version:
Azure AD ally driver for AdonisJS ally
192 lines (191 loc) • 6.99 kB
JavaScript
;
/*
|--------------------------------------------------------------------------
| Ally Oauth driver
|--------------------------------------------------------------------------
|
| This is a dummy implementation of the Oauth driver. Make sure you
|
| - Got through every line of code
| - Read every comment
|
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AAD = void 0;
const standalone_1 = require("@adonisjs/ally/build/standalone");
/**
* Driver implementation. It is mostly configuration driven except the user calls
*
* ------------------------------------------------
* Change "AAD" to something more relevant
* ------------------------------------------------
*/
class AAD extends standalone_1.Oauth2Driver {
constructor(ctx, config) {
super(ctx, config);
this.config = config;
/**
* The URL for the authority data
*
* Do not define query strings in this URL.
*/
/**
* The URL for the redirect request. The user will be redirected on this page
* to authorize the request.
*
* Do not define query strings in this URL.
*/
this.authorizeUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
/**
* The URL to hit to exchange the authorization code for the access token
*
* Do not define query strings in this URL.
*/
this.accessTokenUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
/**
* The URL to hit to get the user details
*
* Do not define query strings in this URL.
*/
this.userInfoUrl = 'https://graph.microsoft.com/v1.0/me';
/**
* The param name for the authorization code. Read the documentation of your oauth
* provider and update the param name to match the query string field name in
* which the oauth provider sends the authorization_code post redirect.
*/
this.codeParamName = 'code';
/**
* The param name for the error. Read the documentation of your oauth provider and update
* the param name to match the query string field name in which the oauth provider sends
* the error post redirect
*/
this.errorParamName = 'error_description';
/**
* Cookie name for storing the CSRF token. Make sure it is always unique. So a better
* approach is to prefix the oauth provider name to `oauth_state` value. For example:
* For example: "facebook_oauth_state"
*/
this.stateCookieName = 'azuread_oauth_state';
/**
* Parameter name to be used for sending and receiving the state from.
* Read the documentation of your oauth provider and update the param
* name to match the query string used by the provider for exchanging
* the state.
*/
this.stateParamName = 'state';
/**
* Parameter name for sending the scopes to the oauth provider.
*/
this.scopeParamName = 'scope';
/**
* The separator indentifier for defining multiple scopes
*/
this.scopesSeparator = ' ';
config.scopes = config.scopes || ['openid', 'profile', 'email', 'offline_access'];
/**
* Extremely important to call the following method to clear the
* state set by the redirect request.
*
* DO NOT REMOVE THE FOLLOWING LINE
*/
this.loadState();
// Perform stateless authentication. Only applicable for Oauth2 client
this.stateless();
}
/**
* Configuring the redirect request with defaults
*/
configureRedirectRequest(request) {
/**
* Define user defined scopes or the default one's
*/
request.scopes(this.config.scopes || ['openid', 'profile', 'email', 'offline_access']);
request.param('client_id', this.config.clientId);
request.param('response_type', 'code');
request.param('response_mode', 'query');
}
/**
* Update the implementation to tell if the error received during redirect
* means "ACCESS DENIED".
*/
accessDenied() {
return this.ctx.request.input('error') === 'invalid_grant';
}
/**
* Returns the HTTP request with the authorization header set
*/
getAuthenticatedRequest(url, token) {
const request = this.httpClient(url);
request.header('Authorization', `Bearer ${token}`);
request.header('Accept', 'application/json');
request.parseAs('json');
return request;
}
/**
* Fetches the user info from the Google API
*/
async getUserInfo(token, callback) {
// User Info
const userRequest = this.getAuthenticatedRequest(this.config.userInfoUrl || this.userInfoUrl, token);
if (typeof callback === 'function') {
callback(userRequest);
}
const userBody = await userRequest.get();
return {
id: userBody.id,
nickName: userBody.id,
displayName: userBody.displayName,
avatarUrl: null,
name: `${userBody.givenName}${userBody.surname ? ` ${userBody.surname}` : ''}`,
email: userBody.mail ? userBody.mail : null,
emailVerificationState: 'unsupported',
original: userBody,
};
}
/**
* Processing the API client response. The child class can overwrite it
* for more control
*/
processClientResponse(client, response) {
/**
* Return json as it is when parsed response as json
*/
if (client.responseType === 'json') {
return response;
}
// return parse(client.responseType === 'buffer' ? response.toString() : response)
}
/**
* Get the user details by query the provider API. This method must return
* the access token and the user details both. Checkout the google
* implementation for same.
*
* https://github.com/adonisjs/ally/blob/develop/src/Drivers/Google/index.ts#L191-L199
*/
async user(callback) {
const accessToken = await this.accessToken();
/**
* Allow end user to configure the request. This should be called after your custom
* configuration, so that the user can override them (if required)
*/
const user = await this.getUserInfo(accessToken.token, callback);
/**
* Write your implementation details here
*/
return {
...user,
token: accessToken,
};
}
/**
* Finds the user by the access token
*/
async userFromToken(token) {
const user = await this.getUserInfo(token);
return {
...user,
token: { token, type: 'bearer' },
};
}
}
exports.AAD = AAD;