177 lines
4.4 KiB
TypeScript
177 lines
4.4 KiB
TypeScript
// PEM ?
|
|
|
|
import { env } from "#config/env";
|
|
import fs from "fs"
|
|
|
|
import {
|
|
JWTToken
|
|
} from "#shared/domain/JWT"
|
|
import axios, { AxiosError } from "axios";
|
|
import { sign } from "node:crypto"
|
|
|
|
type GrantAccessRequestBody = {
|
|
grant_type: string,
|
|
client_id: string,
|
|
client_assertion_type: string,
|
|
client_assertion: string
|
|
}
|
|
|
|
type TokensRequestResponse = {
|
|
"access_token": string,
|
|
"expires_in": number,
|
|
"refresh_token": string
|
|
"refresh_expires_in": number,
|
|
"token_type": "Bearer" | string,
|
|
"not-before-policy": number,
|
|
"session_state": string,
|
|
"scope": string
|
|
}
|
|
|
|
type AuthHeaders = {
|
|
content_type: string,
|
|
sub: string,
|
|
iss: string,
|
|
aud: string,
|
|
jti: string,
|
|
iat: number,
|
|
exp: number,
|
|
}
|
|
|
|
|
|
const GET_TOKEN_URL = "https://idp.docapost.io/auth/realms/GETWAY/protocol/openid-connect/token"
|
|
const REFRESH_TOKEN_URL = GET_TOKEN_URL
|
|
|
|
const DEFAULT_BODY: GrantAccessRequestBody = {
|
|
grant_type: "client_credentials",
|
|
client_id: env.OBJ_CLIENT_ID,
|
|
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
|
client_assertion: env.OBJ_CLI_ASSERTION
|
|
}
|
|
|
|
const REFRESH_BODY = {
|
|
...DEFAULT_BODY,
|
|
grant_type: "refresh_token",
|
|
}
|
|
|
|
const DEFAULT_HEADERS = {
|
|
"content-type": "application/x-www-form-urlencoded"
|
|
}
|
|
|
|
function addIATHeaders(authHeaders: Object) {
|
|
const headers = <AuthHeaders>{
|
|
...authHeaders,
|
|
sub: env.OBJ_CLIENT_ID,
|
|
iss: env.OBJ_CLIENT_ID,
|
|
aud: GET_TOKEN_URL,
|
|
jti: Date.now().toString(),
|
|
iat: Math.floor(Date.now() / 1000),
|
|
exp: Math.floor(Date.now() / 1000) + 5 * 60,
|
|
}
|
|
return headers
|
|
}
|
|
|
|
|
|
/**
|
|
* El servicio gestiona un par de tokens auth - refresh para las
|
|
* operaciones de Objenious.
|
|
* Se puede partir de tokens existentes.
|
|
*/
|
|
export class JWTService {
|
|
|
|
// Igual no deberia mantener estado
|
|
private authToken?: JWTToken<{}>
|
|
private refreshToken?: JWTToken<{}>
|
|
|
|
constructor(args?: {
|
|
token?: string // si se partiese de un token existente,
|
|
refreshToken?: string
|
|
}) {
|
|
if (args?.token != undefined) this.authToken = new JWTToken(args.token)
|
|
if (args?.refreshToken != undefined) this.refreshToken = new JWTToken(args.refreshToken)
|
|
}
|
|
|
|
public async getAccessToken() {
|
|
if (this.authToken != undefined && !this.authToken.isExpired()) {
|
|
console.warn("Se está intentado conseguir un token sin expirar el anterior")
|
|
}
|
|
|
|
console.log("headers", addIATHeaders(DEFAULT_HEADERS))
|
|
console.log("body", DEFAULT_BODY)
|
|
console.log("keypath", __dirname + "/../obj.pem")
|
|
const key = fs.readFileSync(__dirname + "/../obj.pem", "utf8")
|
|
const msg = Buffer.from("test")
|
|
const signature = sign(
|
|
"sha256",
|
|
Buffer.from(msg),
|
|
key
|
|
)
|
|
JWTToken.fromParts({
|
|
header: { alg: "RS256", typ: "JWT", kid: "1234" },
|
|
payload: {
|
|
"iss": "savefamily_rest_ws",
|
|
"aud": "https://idp.docapost.io/auth/realms/GETWAY",
|
|
},
|
|
sigantureData: {
|
|
algorythm: "sha256",
|
|
privateKey: key
|
|
}
|
|
})
|
|
console.log("signature", signature.toString("base64url"))
|
|
|
|
return;
|
|
|
|
const req = axios.post(GET_TOKEN_URL,
|
|
DEFAULT_BODY,
|
|
{
|
|
headers: addIATHeaders(DEFAULT_HEADERS)
|
|
}
|
|
)
|
|
|
|
|
|
|
|
let res;
|
|
|
|
try {
|
|
res = (await req).data as TokensRequestResponse;
|
|
this.authToken = new JWTToken(res.access_token)
|
|
this.refreshToken = new JWTToken(res.refresh_token)
|
|
return this.authToken
|
|
} catch (e) {
|
|
const errorString = "No se ha podido conseguir el token de acceso de OBJENIOUS"
|
|
console.error(errorString, (e as AxiosError).response?.data)
|
|
throw new Error(errorString)
|
|
}
|
|
|
|
}
|
|
|
|
public async tryRefreshToken() {
|
|
if (this.refreshToken == undefined) throw new Error("El refreshToken no está definido")
|
|
if (this.refreshToken.isExpired()) throw new Error("El refreshToken ha expirado")
|
|
|
|
const body = {
|
|
...REFRESH_BODY,
|
|
refresh_token: this.refreshToken.rawToken
|
|
}
|
|
|
|
const req = axios.post(REFRESH_TOKEN_URL,
|
|
body,
|
|
{
|
|
headers: DEFAULT_HEADERS
|
|
}
|
|
)
|
|
|
|
let res;
|
|
try {
|
|
res = (await req).data as TokensRequestResponse;
|
|
this.authToken = new JWTToken(res.access_token)
|
|
this.refreshToken = new JWTToken(res.refresh_token)
|
|
return this.authToken
|
|
} catch (e) {
|
|
const errorString = "No se ha podido conseguir el token de acceso de OBJENIOUS"
|
|
console.error(errorString, e)
|
|
throw new Error(errorString)
|
|
}
|
|
}
|
|
|
|
}
|