Skip to content

Commit

Permalink
Merge pull request #61 from goniszewski/feat/update-api-auth
Browse files Browse the repository at this point in the history
feat: use token-based authentication for API requests
  • Loading branch information
goniszewski authored Feb 13, 2024
2 parents 49d0839 + 11aac55 commit bc42ace
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 6 deletions.
24 changes: 20 additions & 4 deletions src/lib/pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,24 @@ export async function authenticateUserApiRequest(
pb: PocketBase,
request: Request
): Promise<authenticateUserApiRequestResponse> {
const authKey = request.headers.get('Authorization') ?? '';
const authKey = request.headers.get('Authorization')?.split(' ')[1];

if (!authKey) {
return {
owner: '',
disabled: null,
userRecord: null,
error: json(
{
success: false,
error: 'Unauthorized'
},
{
status: 401
}
)
};
}

const response: authenticateUserApiRequestResponse = {
owner: '',
Expand All @@ -134,11 +151,10 @@ export async function authenticateUserApiRequest(
};

try {
const [login, password] = atob(authKey.split(' ')[1]).split(':');

pb.authStore.save(authKey);
const user = await pb
.collection('users')
.authWithPassword(login, password)
.authRefresh()
.then((user) => user.record);

response.owner = user.id;
Expand Down
81 changes: 79 additions & 2 deletions src/routes/api/api-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "Grimoire Integration API",
"version": "0.2.3",
"description": "To authorize, use your user's credentials to create valid authorization header.\n\n Add `[USERNAME OR EMAIL]:[PASSWORD]` and [base64 encode it](https://www.base64encode.org/). Then use the resulting value as the `Authorization` header value, prefixed with `Bearer ` (separated by space). \n\nExample request with proper header (generated from `my-username:my-password`): \n\n```bash\ncurl --request GET \\ \n --url http://[GRIMOIRE_URL]/api/bookmarks \\ \n --header 'Authorization: Bearer bXktdXNlcm5hbWU6bXktcGFzc3dvcmQ='\n```"
"description": "To authorize, pass your user's credentials in a POST request to `/api/auth` to receive the token.\n\nThen use it as the `Authorization` header value, prefixed with `Bearer ` (separated by space). \n\nExample request with proper header: \n\n```bash\ncurl --request GET \\ \n --url http://[GRIMOIRE_URL]/api/bookmarks \\ \n --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'\n```"
},
"servers": [
{
Expand All @@ -27,6 +27,44 @@
}
],
"paths": {
"/auth": {
"post": {
"summary": "Authenticate user",
"description": "Authenticate with your user credentials.",
"operationId": "authenticate",
"requestBody": {
"description": "User credentials",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "User's username or email"
},
"password": {
"type": "string",
"description": "User's password"
}
}
}
}
}
},
"responses": {
"200": {
"$ref": "#/components/responses/AuthSuccess"
},
"400": {
"$ref": "#/components/responses/AuthFailed"
},
"500": {
"$ref": "#/components/responses/ServerError"
}
}
}
},
"/bookmark/simple": {
"post": {
"summary": "Create a new quick bookmark",
Expand Down Expand Up @@ -69,7 +107,7 @@
"required": false,
"schema": {
"type": "string",
"examples": "id1,id2,id3"
"examples": ["id1,id2,id3"]
},
"description": "Comma separated bookmark IDs to retrieve"
}
Expand Down Expand Up @@ -847,6 +885,45 @@
}
},
"responses": {
"AuthFailed": {
"description": "Invalid credentials",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean",
"examples": [false]
},
"error": {
"type": "string"
}
}
}
}
}
},
"AuthSuccess": {
"description": "User authenticated",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean",
"examples": [true]
},
"token": {
"type": "string",
"description": "User token"
}
}
}
}
}
},
"Unauthorized": {
"description": "Unauthorized",
"content": {
Expand Down
56 changes: 56 additions & 0 deletions src/routes/api/auth/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import joi from 'joi';

import { json } from '@sveltejs/kit';

import type { RequestHandler } from '@sveltejs/kit';

export const POST: RequestHandler = async ({ locals, request }) => {
const body = await request.json();

const schema = joi.object({
login: joi.string().required(),
password: joi.string().required()
});

const { value, error } = schema.validate(body);

if (error) {
return json(
{
success: false,
error: error?.message
},
{
status: 400
}
);
}

const { login, password } = value;

try {
const authReponse = await locals.pb.collection('users').authWithPassword(login, password);

const { token } = authReponse;

return json(
{
success: true,
token
},
{
status: 200
}
);
} catch (error: any) {
return json(
{
success: false,
error: error?.message
},
{
status: error?.status || 500
}
);
}
};

0 comments on commit bc42ace

Please sign in to comment.