Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
ignores: ["**/dist/", "**/node_modules/", "**/*.cjs"],
ignores: ["**/dist/", "**/node_modules/", "**/*.cjs", "tests/e2e/ember-app/", "docs-web/.astro/"],
},
{
rules: {
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
},
},
);
45 changes: 45 additions & 0 deletions packages/ember/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "oidc-js-ember",
"version": "0.0.1",
"description": "Ember.js bindings for oidc-js",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"scripts": {
"build": "vite build",
"test": "vitest run",
"lint": "tsc --noEmit"
},
"keywords": [
"oidc",
"openid",
"oauth2",
"ember",
"ember.js",
"glimmer",
"authentication"
],
"author": "eugenioenko",
"license": "MIT",
"dependencies": {
"oidc-js": "workspace:*",
"oidc-js-core": "workspace:*"
},
"devDependencies": {
"typescript": "^5.5.0",
"vite": "^8.0.0",
"vite-plugin-dts": "^4.0.0",
"vitest": "^4.0.0"
}
}
81 changes: 81 additions & 0 deletions packages/ember/src/helpers/require-auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { OidcService } from "../services/oidc.js";
import type { LoginOptions } from "oidc-js";

/**
* Options for the `authenticatedRoute` helper.
*/
export interface AuthenticatedRouteOptions {
/** Whether to automatically refresh expired tokens before redirecting to login. Defaults to true. */
autoRefresh?: boolean;
/** Additional login options passed to the login redirect. */
loginOptions?: LoginOptions;
}

/**
* Route protection helper for Ember routes.
*
* Call this function in a route's `beforeModel` hook to enforce authentication.
* If the user is not authenticated, the helper attempts to refresh the token
* (when `autoRefresh` is true and a refresh token exists). If refresh fails
* or no refresh token is available, the user is redirected to the IdP login page.
*
* The current URL is preserved as the `returnTo` destination so the user returns
* to the protected page after login.
*
* @param service - The OIDC service instance.
* @param transition - The Ember route transition object, used to extract the target URL.
* @param options - Options controlling auto-refresh behavior and login parameters.
*
* @example
* ```typescript
* // app/routes/dashboard.ts
* import Route from '@ember/routing/route';
* import { service } from '@ember/service';
* import { authenticatedRoute } from 'oidc-js-ember';
*
* export default class DashboardRoute extends Route {
* @service declare oidc: OidcService;
*
* async beforeModel(transition) {
* await authenticatedRoute(this.oidc, transition);
* }
* }
* ```
*/
export async function authenticatedRoute(
service: OidcService,
transition: { intent?: { url?: string } },
options: AuthenticatedRouteOptions = {},
): Promise<void> {
const { autoRefresh = true, loginOptions } = options;

if (service.isLoading) {
// Wait for initialization to complete
return;
}

if (service.isAuthenticated) {
// Check if token is expired
const isExpired =
service.tokens.expiresAt !== null &&
service.tokens.expiresAt <= Date.now();

if (!isExpired) {
return;
}

// Token expired, try refresh
if (autoRefresh && service.tokens.refresh) {
try {
await service.refresh();
return;
} catch {
// Refresh failed, fall through to login
}
}
}

// Not authenticated or refresh failed, redirect to login
const returnTo = transition.intent?.url ?? window.location.pathname;
await service.login({ ...loginOptions, returnTo });
}
16 changes: 16 additions & 0 deletions packages/ember/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export { OidcService, createOidcService } from "./services/oidc.js";
export type { OidcServiceConfig } from "./services/oidc.js";

export { authenticatedRoute } from "./helpers/require-auth.js";
export type { AuthenticatedRouteOptions } from "./helpers/require-auth.js";

export type {
IdTokenClaims,
AuthUser,
AuthTokens,
AuthActions,
EmberOidcConfig,
LoginOptions,
} from "./types.js";

export type { OidcConfig, OidcUser, TokenSet } from "oidc-js-core";
Loading
Loading