Skip to content

Commit

Permalink
Allow limiting the hass instance that we fetch auth credentials for (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob authored Jul 10, 2023
1 parent c96cd23 commit 586dc57
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@ You can pass options using the syntax:
getAuth({ hassUrl: "http://localhost:8123" });
```

| Option | Description |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hassUrl | The url where the Home Assistant instance can be reached. This option is needed so we know where to redirect the user for authentication. Once redirected back, it is not needed to pass this option in. |
| clientId | Client ID to use. Client IDs for Home Assistant is the url of your application. Defaults to domain of current page. Pass `null` if you are making requests on behalf of a system user. |
| redirectUrl | The url to redirect back to when the user has logged in. Defaults to current page. |
| saveTokens | Function to store an object containing the token information. |
| loadTokens | Function that returns a promise that resolves to previously stored token information object or undefined if no info available. |
| authCode | If you have an auth code received via other means, you can pass it in and it will be used to fetch tokens instead of going through the OAuth2 flow. |
| Option | Description |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hassUrl | The url where the Home Assistant instance can be reached. This option is needed so we know where to redirect the user for authentication. Once redirected back, it is not needed to pass this option in. |
| clientId | Client ID to use. Client IDs for Home Assistant is the url of your application. Defaults to domain of current page. Pass `null` if you are making requests on behalf of a system user. |
| redirectUrl | The url to redirect back to when the user has logged in. Defaults to current page. |
| saveTokens | Function to store an object containing the token information. |
| loadTokens | Function that returns a promise that resolves to previously stored token information object or undefined if no info available. |
| authCode | If you have an auth code received via other means, you can pass it in and it will be used to fetch tokens instead of going through the OAuth2 flow. |
| limitHassInstance | If set to true, allow only authentication credentials for the passed in `hassUrl` and `clientId`. Defaults to false. |

In certain instances `getAuth` will raise an error. These errors can be imported from the package:

Expand All @@ -90,6 +91,7 @@ HAWS.ERR_HASS_HOST_REQUIRED;
| `ERR_HASS_HOST_REQUIRED` | You need to pass in `hassUrl` to `getAuth` to continue getting auth. This option is not needed when the user is redirected back after successfully logging in. |
| `ERR_INVALID_AUTH` | This error will be raised if the url contains an authorization code that is no longer valid. |
| `ERR_INVALID_HTTPS_TO_HTTP` | This error is raised if your code is being run from a secure context (hosted via https) and you're trying to fetch tokens from a Home Assistant instance via a non secure context (http). This is called [mixed active content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content#Mixed_active_content) and the browser forbids this. |
| `ERR_INVALID_AUTH_CALLBACK` | This error is raised if only credentials for the specified Home Assistant instance are allowed and the client ID or hassURL in the auth callback state do not match the expected ones. |
| Other errors | Unknown error! |

### `createConnection()`
Expand Down
13 changes: 12 additions & 1 deletion lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { parseQuery } from "./util.js";
import {
ERR_HASS_HOST_REQUIRED,
ERR_INVALID_AUTH,
ERR_INVALID_AUTH_CALLBACK,
ERR_INVALID_HTTPS_TO_HTTP,
} from "./errors.js";

Expand All @@ -24,6 +25,7 @@ export type getAuthOptions = {
authCode?: string;
saveTokens?: SaveTokensFunc;
loadTokens?: LoadTokensFunc;
limitHassInstance?: boolean;
};

type QueryCallbackData =
Expand Down Expand Up @@ -244,9 +246,10 @@ export async function getAuth(options: getAuthOptions = {}): Promise<Auth> {
}
const clientId =
options.clientId !== undefined ? options.clientId : genClientId();
const limitHassInstance = options.limitHassInstance === true;

// Use auth code if it was passed in
if (!data && options.authCode && hassUrl) {
if (options.authCode && hassUrl) {
data = await fetchToken(hassUrl, clientId, options.authCode);
if (options.saveTokens) {
options.saveTokens(data);
Expand All @@ -261,6 +264,14 @@ export async function getAuth(options: getAuthOptions = {}): Promise<Auth> {
if ("auth_callback" in query) {
// Restore state
const state = decodeOAuthState(query.state);

if (
limitHassInstance &&
(state.hassUrl !== hassUrl || state.clientId !== clientId)
) {
throw ERR_INVALID_AUTH_CALLBACK;
}

data = await fetchToken(state.hassUrl, state.clientId, query.code);
if (options.saveTokens) {
options.saveTokens(data);
Expand Down
1 change: 1 addition & 0 deletions lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export const ERR_INVALID_AUTH = 2;
export const ERR_CONNECTION_LOST = 3;
export const ERR_HASS_HOST_REQUIRED = 4;
export const ERR_INVALID_HTTPS_TO_HTTP = 5;
export const ERR_INVALID_AUTH_CALLBACK = 6;

0 comments on commit 586dc57

Please sign in to comment.