diff --git a/Makefile b/Makefile index 994a3f8b2..fdffe39d8 100644 --- a/Makefile +++ b/Makefile @@ -23,12 +23,12 @@ get-version: ## Return version. .PHONY: dev -dev: check-port install dev-env-up ## Start development environment. +dev: check-port dev-env-up ## Start development environment. bash -c "trap 'make dev-env-down' EXIT; pnpm dev:start" .PHONY: test -test: check-port install dev-env-up ## Run end-to-end tests. +test: check-port dev-env-up ## Run end-to-end tests. pnpm test .PHONY: check-port @@ -36,7 +36,7 @@ check-port: [ -z $$(lsof -t -i tcp:$(PORT)) ] || (echo "The port $(PORT) is already in use"; exit 1;) .PHONY: docgen -docgen: check-port install dev-env-up ## Generate the openapi.json file. +docgen: check-port dev-env-up ## Generate the openapi.json file. AUTH_CLIENT_URL=https://my-app.com AUTH_LOG_LEVEL=error AUTH_ACCESS_CONTROL_ALLOWED_REDIRECT_URLS= pnpm dev & while [ "$$(curl -s -o /dev/null -w ''%{http_code}'' http://localhost:$(PORT)/healthz)" != "200" ]; do sleep 1; done curl http://localhost:$(PORT)/openapi.json | json_pp > docs/openapi.json @@ -45,28 +45,27 @@ docgen: check-port install dev-env-up ## Generate the openapi.json file. .PHONY: watch -watch: check-port install dev-env-up ## Start tests in watch mode. +watch: check-port dev-env-up ## Start tests in watch mode. bash -c "trap 'make dev-env-down' EXIT; pnpm test:watch" .PHONY: build -build: +build: docker build -t $(IMAGE) . -.PHONY: dev-env-down +.PHONY: dev-env-down dev-env-up: ## Start required services (Hasura, Postgres, Mailhog). - docker-compose -f docker-compose.yaml up -d + docker compose -f docker-compose.yaml up -d while [ "$$(curl -s -o /dev/null -w ''%{http_code}'' http://localhost:8080/healthz)" != "200" ]; do sleep 1; done @echo "Hasura is ready"; .PHONY: dev-env-down dev-env-down: ## Stop required services (Hasura, Posgres, Mailhbg). - docker-compose -f docker-compose.yaml down + docker compose -f docker-compose.yaml down .PHONY: install -install: +install: pnpm install - diff --git a/docs/openapi.json b/docs/openapi.json index 8be26ee7f..eaf6c6458 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -37,7 +37,7 @@ }, "status" : { "enum" : [ - 404 + 409 ] } }, @@ -232,6 +232,27 @@ }, "type" : "object" }, + "InvalidExpiryDateError" : { + "additionalProperties" : false, + "properties" : { + "error" : { + "enum" : [ + "invalid-expiry-date" + ] + }, + "message" : { + "enum" : [ + "The expiry date must be greater than the current date" + ] + }, + "status" : { + "enum" : [ + 400 + ] + } + }, + "type" : "object" + }, "InvalidOauthConfigurationError" : { "additionalProperties" : false, "properties" : { @@ -274,6 +295,27 @@ }, "type" : "object" }, + "InvalidPatError" : { + "additionalProperties" : false, + "properties" : { + "error" : { + "enum" : [ + "invalid-pat" + ] + }, + "message" : { + "enum" : [ + "Invalid or expired personal access token" + ] + }, + "status" : { + "enum" : [ + 401 + ] + } + }, + "type" : "object" + }, "InvalidRefreshTokenError" : { "additionalProperties" : false, "properties" : { @@ -1479,7 +1521,7 @@ "type" : "object" }, "Version" : { - "example" : "0.17.1", + "example" : "0.21.2", "type" : "string" } }, @@ -1498,7 +1540,7 @@ }, "termsOfService" : "", "title" : "Hasura auth", - "version" : "0.17.1" + "version" : "0.21.2" }, "openapi" : "3.0.0", "paths" : { @@ -1565,6 +1607,60 @@ ] } }, + "/pat" : { + "post" : { + "deprecated" : false, + "parameters" : [], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CreatePATSchema" + } + } + }, + "description" : "", + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SessionModel" + } + } + }, + "description" : "User successfully authenticated" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InvalidRequestError" + } + } + }, + "description" : "The payload is invalid" + }, + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/UnauthorizedError" + } + } + }, + "description" : "Unauthenticated user or invalid token" + } + }, + "security" : [], + "summary" : "Create a Personal Access Token (PAT)", + "tags" : [ + "General" + ] + } + }, "/signin/anonymous" : { "post" : { "deprecated" : false, @@ -1919,6 +2015,60 @@ ] } }, + "/signin/pat" : { + "post" : { + "deprecated" : false, + "parameters" : [], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SignInPATSchema" + } + } + }, + "description" : "", + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SessionPayload" + } + } + }, + "description" : "User successfully authenticated" + }, + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/InvalidRequestError" + } + } + }, + "description" : "The payload is invalid" + }, + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DisabledEndpointError" + } + } + }, + "description" : "The feature is not activated" + } + }, + "security" : [], + "summary" : "Sign in with a Personal Access Token (PAT)", + "tags" : [ + "Authentication" + ] + } + }, "/signin/provider/{provider}" : { "get" : { "deprecated" : false, diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..dd692c85f --- /dev/null +++ b/flake.lock @@ -0,0 +1,77 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1694434370, + "narHash": "sha256-7yfdTR4mCvWZ39Q6HUcsa18tr0mg+fJZSaHE/63rwoo=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "d6381c442f79f2f1fdfde00521c3d15d6c21218e", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1694562957, + "narHash": "sha256-ZvDt5bxX6Ga+TQ6kvK5WEn7OQN87KAsMaRrFSdReIm8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f4a33546bdb5f81bd6cceb1b3cb19667145fed83", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..e6bc27707 --- /dev/null +++ b/flake.nix @@ -0,0 +1,99 @@ +{ + description = "Nhost Hasura Auth"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + nix-filter.url = "github:numtide/nix-filter"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils, nix-filter }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ + (final: prev: { + nodejs = prev.nodejs-18_x; + }) + ]; + + pkgs = import nixpkgs { + inherit overlays system; + }; + + nix-src = nix-filter.lib.filter { + root = ./.; + include = [ + (nix-filter.lib.matchExt "nix") + ]; + }; + + node_modules = pkgs.stdenv.mkDerivation { + inherit version; + + pname = "node_modules"; + + nativeBuildInputs = with pkgs; [ + nodePackages.pnpm + ]; + + src = nix-filter.lib.filter { + root = ./.; + include = [ + ./package.json + ./pnpm-lock.yaml + ]; + }; + + + buildPhase = '' + pnpm install + ''; + + installPhase = '' + mkdir -p $out + cp -r node_modules $out + ''; + }; + + + name = "hasura-auth"; + version = "0.0.0-dev"; + + buildInputs = [ ]; + nativeBuildInputs = with pkgs; [ + nodePackages.pnpm + ]; + in + { + checks = { + nixpkgs-fmt = pkgs.runCommand "check-nixpkgs-fmt" + { + nativeBuildInputs = with pkgs; + [ + nixpkgs-fmt + ]; + } + '' + mkdir $out + nixpkgs-fmt --check ${nix-src} + ''; + + }; + + devShells = flake-utils.lib.flattenTree rec { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + nixpkgs-fmt + gnumake + ] ++ buildInputs ++ nativeBuildInputs; + + shellHook = '' + export PATH=${node_modules}/node_modules/.bin:$PATH + rm -rf node_modules + ln -sf ${node_modules}/node_modules/ node_modules + ''; + }; + }; + } + ); +} diff --git a/src/utils/__generated__/graphql-request.ts b/src/utils/__generated__/graphql-request.ts index 70af2c9e4..27f05a81b 100644 --- a/src/utils/__generated__/graphql-request.ts +++ b/src/utils/__generated__/graphql-request.ts @@ -525,13 +525,6 @@ export type AuthRefreshTokenTypes_Mutation_Response = { returning: Array; }; -/** input type for inserting object relation for remote table "auth.refresh_token_types" */ -export type AuthRefreshTokenTypes_Obj_Rel_Insert_Input = { - data: AuthRefreshTokenTypes_Insert_Input; - /** upsert condition */ - on_conflict?: InputMaybe; -}; - /** on_conflict condition type for table "auth.refresh_token_types" */ export type AuthRefreshTokenTypes_On_Conflict = { constraint: AuthRefreshTokenTypes_Constraint; @@ -601,8 +594,6 @@ export type AuthRefreshTokens = { id: Scalars['uuid']; metadata?: Maybe; refreshTokenHash?: Maybe; - /** An object relationship */ - refresh_token_type: AuthRefreshTokenTypes; type: AuthRefreshTokenTypes_Enum; /** An object relationship */ user: Users; @@ -677,7 +668,6 @@ export type AuthRefreshTokens_Bool_Exp = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe; @@ -711,7 +701,6 @@ export type AuthRefreshTokens_Insert_Input = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe; @@ -778,7 +767,6 @@ export type AuthRefreshTokens_Order_By = { id?: InputMaybe; metadata?: InputMaybe; refreshTokenHash?: InputMaybe; - refresh_token_type?: InputMaybe; type?: InputMaybe; user?: InputMaybe; userId?: InputMaybe;