@poppinss/oauth-client
Version:
A framework agnostic package to implement "Login with" flow using OAuth compliant authorization servers.
280 lines (279 loc) • 5.99 kB
JavaScript
import { Exception, createError } from "@poppinss/exception";
import ky from "ky";
import { debuglog } from "node:util";
//#region \0rolldown/runtime.js
var __defProp = Object.defineProperty;
var __exportAll = (all, no_symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
//#endregion
//#region src/errors.ts
var errors_exports = /* @__PURE__ */ __exportAll({
E_OAUTH_MISSING_TOKEN: () => E_OAUTH_MISSING_TOKEN,
E_OAUTH_STATE_MISMATCH: () => E_OAUTH_STATE_MISMATCH
});
/**
* Raised when unable to get access token for oauth2 or oauth token and secret
* for oauth1
*/
const E_OAUTH_MISSING_TOKEN = class MissingTokenException extends Exception {
static status = 400;
static code = "E_OAUTH_MISSING_TOKEN";
static oauth2Message = "Invalid oauth2 response. Missing \"access_token\"";
static oauth1Message = "Invalid oauth1 response. Missing \"oauth_token\" and \"oauth_token_secret\"";
};
/**
* Raised when unable to verify the CSRF state post redirect
*/
const E_OAUTH_STATE_MISMATCH = createError("Unable to verify re-redirect state", "E_OAUTH_STATE_MISMATCH", 400);
//#endregion
//#region src/debug.ts
var debug_default = debuglog("oauth_client");
//#endregion
//#region src/http_client.ts
/**
* An HTTP client abstraction we need for making OAuth requests
*/
var HttpClient = class {
#baseUrl;
/**
* Request string params
*/
#params = {};
/**
* Form fields to send
*/
#fields = {};
/**
* Headers to send
*/
#headers = {};
/**
* Oauth1 params
*/
#oauth1Params = {};
/**
* The request body type.
*
* - The content type will be set to `application/json`
* for a json request type.
* - The content type will be set to `application/x-www-form-urlencoded`
* for a urlencoded request type.
*/
#requestType = "urlencoded";
/**
* Expected response body type.
*/
#responseType = "text";
constructor(baseUrl) {
this.#baseUrl = baseUrl;
}
/**
* Returns the got options for the request
*/
#getRequestOptions() {
const hasBody = Object.keys(this.#fields).length > 0;
const hasParams = Object.keys(this.#params).length > 0;
return {
...hasBody ? this.#requestType === "json" ? { json: this.#fields } : { body: new URLSearchParams(this.#fields) } : {},
...hasParams ? { searchParams: this.#params } : {},
headers: this.#headers
};
}
/**
* Returns the response body of the got instance
*/
#getResponseBody(request) {
if (this.#responseType === "json") return request.json();
return request.text();
}
/**
* Get access to request query params
*/
getParams() {
return this.#params;
}
/**
* Get access to request headers
*/
getHeaders() {
return this.#headers;
}
/**
* Get access to request body fields
*/
getFields() {
return this.#fields;
}
/**
* Get access to request oAuth1 params
*/
getOauth1Params() {
return this.#oauth1Params;
}
/**
* Get the request type
*/
getRequestType() {
return this.#requestType;
}
/**
* Get the type of the desired response type
*/
getResponseType() {
return this.#responseType;
}
/**
* Define query string param
*/
param(key, value) {
this.#params[key] = value;
return this;
}
/**
* Remove a named param
*/
clearParam(key) {
delete this.#params[key];
return this;
}
/**
* Define an oauth1 param that makes it way to the Authorization
* header
*/
oauth1Param(key, value) {
this.#oauth1Params[key] = value;
return this;
}
/**
* Remove a named oauth1Param
*/
clearOauth1Param(key) {
delete this.#oauth1Params[key];
return this;
}
/**
* Define request body
*/
field(key, value) {
this.#fields[key] = value;
return this;
}
/**
* Remove a field by its name
*/
clearField(key) {
delete this.#fields[key];
return this;
}
/**
* Define request header
*/
header(key, value) {
this.#headers[key] = value;
return this;
}
/**
* Remove a header by its name
*/
clearHeader(key) {
delete this.#headers[key];
return this;
}
/**
* Set the request content type.
*/
sendAs(type) {
this.#requestType = type;
return this;
}
/**
* Define how to parse the response
*/
parseAs(type) {
this.#responseType = type;
return this;
}
/**
* Reset the client state
*/
clear() {
this.#requestType = "urlencoded";
this.#responseType = "text";
this.#params = {};
this.#fields = {};
this.#headers = {};
this.#oauth1Params = {};
return this;
}
/**
* Make a post request
*/
async post() {
const options = this.#getRequestOptions();
debug_default("making POST request url: \"%s\" options: %O", this.#baseUrl, options);
return this.#getResponseBody(ky.post(this.#baseUrl, options));
}
/**
* Make a get request
*/
async get() {
const options = this.#getRequestOptions();
debug_default("making GET request url: \"%s\" options:%O", this.#baseUrl, options);
return this.#getResponseBody(ky.get(this.#baseUrl, options));
}
};
//#endregion
//#region src/url_builder.ts
/**
* Fluent API to constructor a URL with query string
*/
var UrlBuilder = class {
#url;
constructor(baseUrl) {
this.#url = new URL(baseUrl);
}
/**
* Returns URL params as an object
*/
getParams() {
const params = {};
for (const [key, value] of this.#url.searchParams.entries()) params[key] = value;
return params;
}
/**
* Define the request param
*/
param(key, value) {
this.#url.searchParams.append(key, value);
return this;
}
/**
* Clear a specific param
*/
clearParam(key) {
this.#url.searchParams.delete(key);
return this;
}
/**
* Clear all params
*/
clear() {
Array.from(this.#url.searchParams.keys()).forEach((key) => this.clearParam(key));
return this;
}
/**
* Returns the url
*/
makeUrl() {
return this.#url.toString();
}
};
//#endregion
export { E_OAUTH_STATE_MISMATCH as a, E_OAUTH_MISSING_TOKEN as i, HttpClient as n, errors_exports as o, debug_default as r, UrlBuilder as t };