English | 日本語
OpenID Connect client (RP, Relying Party) plugin for ElysiaJS, wrapping openid-client.
Authorization Code Flow
is supported.Confidential Client
is supported.client_secret
is requiredresponse_types
is fixed to ["code"]
response_type
is fixed to code
response_mode
must set to query
or not setcode_challenge
, state
and nonce
are generated automaticallycode_challenge_method
is fixed to S256
openid
is automatically added to scope
bun add elysia-openid-client
import Elysia from "elysia";
import { OidcClient } from "elysia-openid-client";
const rp = await OidcClient.create({
baseUrl: "https://app.example.com", // RP URL
issuerUrl: "https://issuer.example.com", // OP URL
clientMetadata: {
client_id: "client-id",
client_secret: "client-secret",
},
});
const endpoints = rp.getEndpoints(); // Endpoints plugin
const hook = rp.getAuthHook(); // Auth hook plugin
console.log(rp.issuerMetadata); // Show OP metadata
new Elysia()
.use(endpoints) // Add endpoints
.guard((app) => // Define restricted area
app
.use(hook) // Add onBeforeHandle hook for authentication/authorization
.onBeforeHandle(({ sessionStatus, sessionClaims }) => {
// Authorization by name, mail, group, etc.
})
.get("/", ({ sessionStatus }) => sessionStatus ? "Logged in" : "Restricted")
.get("/status", ({ sessionStatus }) => sessionStatus)
.get("/claims", ({ sessionClaims }) => sessionClaims),
)
.get("/free", () => "Not restricted")
.get("/logout", () => "Logout completed")
.listen(80);
interface OIDCClientOptions {
issuerUrl: string;
baseUrl: string;
settings?: Partial<OIDCClientSettings>;
cookieSettings?: Partial<OIDCClientCookieSettings>;
dataAdapter?: OIDCClientDataAdapter;
logger?: OIDCClientLogger | null;
clientMetadata: ClientMetadata & {
client_secret: string;
};
authParams?: AuthorizationParameters;
}
const options: OIDCClientOptions = {
// ...
}
const rp = await OidcClient.create(options);
issuerUrl
https://github.com
baseUrl
https:/your-service.example.com
Data Adapter
section in this document.Logger
section in this document.ClientMetadata
ClientMetadata
type definition of openid-client
.OpenID Connect Dynamic Client Registration 1.0
.AuthorizationParameters
AuthorizationParameters
type definition of openid-client
.OpenID Connect Core 1.0
.elysia-openid-client-endpoints
settings.pluginSeed
or else issuerUrl
/auth/login
)client.authorizationUrl
of openid-client./auth/callback
)client.callbackParams
and client.callback
of openid-client./auth/logout
)client.endSessionUrl
of openid-client./auth/userinfo
)client.userinfo
of openid-client./auth/introspect
)client.introspect
of openid-client./auth/refresh
)client.refresh
of openid-client./auth/resource?url=<resource-url>
)client.requestResource
of openid-client./auth/revoke
)client.revoke
of openid-client.204
/auth/status
)/auth/claims
)Determine the validity of the session in onBeforeHandle
, and return sessionStatus
and sessionClaims
from the resolve
hook.
const rp = await OidcClient.create({ ... });
const hookOptions: AuthHookOptions = { ... };
const hook = rp.getAuthHook(hookOptions);
sessionStatus
: Session status
sessionClaims
: ID Token ClaimsIdTokenClaims
type definition of openid-client
.OpenID Connect Core 1.0
.loginRedirectUrl
.disableRedirect
is true
, both sessionStatus
and sessionClaims
will be null
.elysia-openid-client-auth-hook
settings.pluginSeed
or else issuerUrl
Defines how session data is stored.
const rp = await OidcClient.create({
//...
dataAdapter: OIDCClientDataAdapter,
//...
})
Use Bun built-in SQLite driver.
import { SQLiteAdapter } from 'elysia-openid-client/dataAdapters/SQLiteAdapter';
// In-memory
const memoryAdapter = new SQLiteAdapter();
// Same as `new SQLiteAdapter({ filename: ":memory:" })`
// Persistence to file
const fileAdapter = new SQLiteAdapter({
filename: "path/to/sessions.sqlite"
});
Use LokiJS.
bun add lokijs
bun add -D @types/lokijs
// In-memory
import { LokiInMemoryAdapter } from 'elysia-openid-client/dataAdapters/LokiInMemoryAdapter';
const memoryAdapter = new LokiInMemoryAdapter();
// Persistence to file
import { LokiFileAdapter } from 'elysia-openid-client/dataAdapters/LokiFileAdapter';
const fileAdapter = await LokiFileAdapter.create({
filename: "path/to/sessions.db"
});
Use Lowdb.
bun add lowdb
import { LowdbAdapter } from 'elysia-openid-client/dataAdapters/LowdbAdapter';
// In-memory
const memoryAdapter = await LowdbAdapter.create();
// Persistence to file
const fileAdapter = await LowdbAdapter.create({
filename: "sessions.json",
})
bun add ioredis
import { RedisAdapter } from 'elysia-openid-client/dataAdapters/RedisAdapter';
const redisAdapter = new RedisAdapter({
port: 6379,
host: "localhost",
});
// MyDataAdapter.ts
import type { OIDCClientDataAdapter } from 'elysia-openid-client';
export class MyDataAdapter implements OIDCClientDataAdapter {
// ...
}
// app.ts
import { MyDataAdapter } from 'path/to/MyDataAdapter';
const rp = await OidcClient.create({
//...
dataAdapter: new MyDataAdapter(),
//...
})
Defines logger.
const rp = await OidcClient.create({
//...
logger: OIDCClientLogger | null,
//...
})
consoleLogger("info")
.null
, disable logging.silent
:trace
:debug
:info
:warn
:error
:fatal
:Assign pino directly.
bun add pino
import pino from "pino";
const rp = await OidcClient.create({
//...
logger: pino(),
//...
})
Using Console.
import { consoleLogger } from "elysia-openid-client/loggers/consoleLogger";
const minimumLogLevel = "debug"; // same as pino
const rp = await OidcClient.create({
//...
logger: consoleLogger(minimumLogLevel),
//...
})
See OIDCClientLogger and consoleLogger
implementation.
If you are using GitHub Copilot to generate suggested code, you must set the Suggestions matching public code
option to Block
. If you are using a similar service with a similar option, you must do the same.