diff --git a/README.md b/README.md index 2a3a139..5a7086e 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,14 @@ Protected calls use metadata: authorization: Bearer ``` +## Postman + +Postman helper files are available in `postman/`: + +- `Gapido Auth gRPC.postman_environment.json` +- `Gapido Auth gRPC.postman_collection.json` +- `README.md` with gRPC request setup steps + ## Security Notes - OTP codes are generated with `secrets`, stored only as HMAC hashes in Redis, and expire after 120 seconds by default. diff --git a/postman/Gapido Auth gRPC.postman_collection.json b/postman/Gapido Auth gRPC.postman_collection.json new file mode 100644 index 0000000..be519c3 --- /dev/null +++ b/postman/Gapido Auth gRPC.postman_collection.json @@ -0,0 +1,225 @@ +{ + "info": { + "_postman_id": "9f8dcf04-ff26-48a8-bb0f-bc5294c6f001", + "name": "Gapido Auth gRPC", + "description": "Collection-style reference for the Gapido Auth gRPC service. Use Postman's gRPC request builder with proto/gapido_auth/generated/auth.proto. Standard Postman collection JSON is HTTP-oriented, so these items document the gRPC method names, metadata, and request payloads.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "RequestOtp", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/RequestOtp", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "RequestOtp" + ] + }, + "body": { + "mode": "raw", + "raw": "{\n \"mobile\": \"{{mobile}}\",\n \"purpose\": \"{{purpose}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/RequestOtp. Public method. In debug SMS mode, fetch the OTP from the demo UI or Redis debug key." + } + }, + { + "name": "VerifyOtp", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/VerifyOtp", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "VerifyOtp" + ] + }, + "body": { + "mode": "raw", + "raw": "{\n \"mobile\": \"{{mobile}}\",\n \"code\": \"{{otp_code}}\",\n \"purpose\": \"{{purpose}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/VerifyOtp. Save access_token and refresh_token from the response into the Postman environment." + } + }, + { + "name": "RefreshToken", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/RefreshToken", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "RefreshToken" + ] + }, + "body": { + "mode": "raw", + "raw": "{\n \"refresh_token\": \"{{refresh_token}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/RefreshToken. This rotates the refresh token; replace both token variables after a successful response." + } + }, + { + "name": "RevokeRefreshToken", + "request": { + "method": "POST", + "header": [ + { + "key": "authorization", + "value": "Bearer {{access_token}}", + "type": "text" + } + ], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/RevokeRefreshToken", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "RevokeRefreshToken" + ] + }, + "body": { + "mode": "raw", + "raw": "{\n \"refresh_token\": \"{{refresh_token}}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/RevokeRefreshToken. Metadata: authorization = Bearer {{access_token}}." + } + }, + { + "name": "PublicPing", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/PublicPing", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "PublicPing" + ] + }, + "body": { + "mode": "raw", + "raw": "{}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/PublicPing. Public method." + } + }, + { + "name": "UserOnly", + "request": { + "method": "POST", + "header": [ + { + "key": "authorization", + "value": "Bearer {{access_token}}", + "type": "text" + } + ], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/UserOnly", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "UserOnly" + ] + }, + "body": { + "mode": "raw", + "raw": "{}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/UserOnly. Metadata: authorization = Bearer {{access_token}}." + } + }, + { + "name": "AdminOnly", + "request": { + "method": "POST", + "header": [ + { + "key": "authorization", + "value": "Bearer {{access_token}}", + "type": "text" + } + ], + "url": { + "raw": "grpc://{{grpc_host}}/gapido.auth.v1.AuthService/AdminOnly", + "protocol": "grpc", + "host": [ + "{{grpc_host}}" + ], + "path": [ + "gapido.auth.v1.AuthService", + "AdminOnly" + ] + }, + "body": { + "mode": "raw", + "raw": "{}", + "options": { + "raw": { + "language": "json" + } + } + }, + "description": "gRPC method: gapido.auth.v1.AuthService/AdminOnly. Metadata: authorization = Bearer {{access_token}}. Requires the configured admin mobile." + } + } + ] +} + diff --git a/postman/Gapido Auth gRPC.postman_environment.json b/postman/Gapido Auth gRPC.postman_environment.json new file mode 100644 index 0000000..f57baab --- /dev/null +++ b/postman/Gapido Auth gRPC.postman_environment.json @@ -0,0 +1,45 @@ +{ + "id": "3bfc0609-8d8d-4e1f-8e58-2fca3f1fc001", + "name": "Gapido Auth gRPC Local", + "values": [ + { + "key": "grpc_host", + "value": "localhost:50051", + "type": "default", + "enabled": true + }, + { + "key": "mobile", + "value": "989120000000", + "type": "default", + "enabled": true + }, + { + "key": "purpose", + "value": "login", + "type": "default", + "enabled": true + }, + { + "key": "otp_code", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "access_token", + "value": "", + "type": "secret", + "enabled": true + }, + { + "key": "refresh_token", + "value": "", + "type": "secret", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_using": "Gapido Auth Service" +} + diff --git a/postman/README.md b/postman/README.md new file mode 100644 index 0000000..f6031ee --- /dev/null +++ b/postman/README.md @@ -0,0 +1,67 @@ +# Postman gRPC Guide + +Use these files with the running Docker Compose stack: + +```bash +docker compose up --build +``` + +Import `Gapido Auth gRPC.postman_environment.json` into Postman and select it as the active environment. + +## Create the gRPC Requests + +Postman's HTTP collection JSON is not a perfect carrier for executable gRPC requests. Use `Gapido Auth gRPC.postman_collection.json` as a request reference, then create gRPC requests in Postman with: + +- Server URL: `{{grpc_host}}` +- Proto file: `proto/gapido_auth/generated/auth.proto` +- Service: `gapido.auth.v1.AuthService` + +## Request Order + +1. `RequestOtp` + +```json +{ + "mobile": "{{mobile}}", + "purpose": "{{purpose}}" +} +``` + +2. Get the OTP. + +With local debug mode, open `http://localhost:8080`, enter the same mobile number, and use `Use Debug OTP`; or read the Redis key: + +```text +debug:sms:last:{{mobile}} +``` + +3. `VerifyOtp` + +```json +{ + "mobile": "{{mobile}}", + "code": "{{otp_code}}", + "purpose": "{{purpose}}" +} +``` + +Copy `access_token` and `refresh_token` from the response into the active Postman environment. + +4. Protected calls + +For `UserOnly`, `AdminOnly`, and `RevokeRefreshToken`, add metadata: + +```text +authorization: Bearer {{access_token}} +``` + +5. `RefreshToken` + +```json +{ + "refresh_token": "{{refresh_token}}" +} +``` + +Refresh rotates the refresh token, so update both token variables after a successful response. +