better_auth-oauth-provider 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +152 -3
- data/lib/better_auth/oauth_provider/version.rb +1 -1
- data/lib/better_auth/plugins/oauth_provider.rb +827 -90
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24a78dcb3a3ee2da7f9f62938f167887fb30b6b1f7585cf35a003be2bcf0bf3b
|
|
4
|
+
data.tar.gz: 0cfb1cd9eacabfd74a979b335f3fc482ddc79110781cb2473cc19c007af0ab34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e6642f06f181d19b533af40736184e5e129786ae7461e73d8206ff2c5b2958f66bd4fa69c15da22bb617da0d4fec3295f54d3c6475e892b0b7262f35adfac31
|
|
7
|
+
data.tar.gz: 07a111e2a9d439de5fb060818e23a6bc49ca67b8f270321fd3c400be8be65e7a7e77384831accbfef180d3044fb28b9b2b7995c379ee44f72044f7351dba4056
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.2.0 - 2026-04-29
|
|
6
|
+
|
|
7
|
+
- Aligned OAuth provider server behavior with upstream `@better-auth/oauth-provider` v1.6.9: upstream-shaped client and consent CRUD routes, server-only admin client routes, discovery metadata auth-method and signing-alg semantics, canonical access-token and consent schema, dynamic-registration PKCE defaults, refresh replay cascade revocation, rotate-secret response shape, and pairwise sector identifiers.
|
|
8
|
+
- Added upstream-parity OAuth provider behavior for dynamic client registration controls, PKCE enforcement, consent management, client management, token prefixes, refresh rotation, JWT resource access tokens, pairwise subjects, userinfo claims, introspection/revocation hints, end-session, `/oauth2/continue`, metadata cache headers, conditional JWKS metadata, and rate limits.
|
|
9
|
+
- Updated package and docs examples to use executable registration and token exchange flows.
|
|
10
|
+
|
|
3
11
|
## 0.1.0
|
|
4
12
|
|
|
5
13
|
- Initial package skeleton for Better Auth OAuth provider.
|
data/README.md
CHANGED
|
@@ -2,17 +2,166 @@
|
|
|
2
2
|
|
|
3
3
|
External OAuth provider plugin package for `better_auth`.
|
|
4
4
|
|
|
5
|
-
Upstream ships OAuth provider as `@better-auth/oauth-provider`, separate from core plugin exports. This gem mirrors that boundary for Ruby.
|
|
5
|
+
Upstream ships OAuth provider as `@better-auth/oauth-provider`, separate from core plugin exports. This gem mirrors that boundary for Ruby while keeping Ruby option names snake_case and upstream-compatible HTTP paths and JSON keys.
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
8
|
require "better_auth"
|
|
9
9
|
require "better_auth/oauth_provider"
|
|
10
10
|
|
|
11
|
-
BetterAuth.auth(
|
|
11
|
+
auth = BetterAuth.auth(
|
|
12
|
+
secret: ENV.fetch("BETTER_AUTH_SECRET"),
|
|
13
|
+
base_url: "https://auth.example.com/api/auth",
|
|
12
14
|
plugins: [
|
|
13
|
-
BetterAuth::Plugins.oauth_provider
|
|
15
|
+
BetterAuth::Plugins.oauth_provider(
|
|
16
|
+
scopes: ["openid", "profile", "email", "offline_access"],
|
|
17
|
+
consent_page: "/oauth2/consent",
|
|
18
|
+
allow_dynamic_client_registration: true
|
|
19
|
+
)
|
|
14
20
|
]
|
|
15
21
|
)
|
|
16
22
|
```
|
|
17
23
|
|
|
24
|
+
## Client Registration
|
|
25
|
+
|
|
26
|
+
Dynamic registration is disabled by default. Enable it explicitly and call it with an authenticated session unless unauthenticated registration is also enabled.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
client = auth.api.register_o_auth_client(
|
|
30
|
+
headers: {"cookie" => session_cookie},
|
|
31
|
+
body: {
|
|
32
|
+
client_name: "Example Client",
|
|
33
|
+
redirect_uris: ["https://client.example.com/callback"],
|
|
34
|
+
token_endpoint_auth_method: "client_secret_post",
|
|
35
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
36
|
+
response_types: ["code"],
|
|
37
|
+
scope: "openid profile offline_access"
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Authorization Code Token Exchange
|
|
43
|
+
|
|
44
|
+
Authorization code clients use S256 PKCE by default.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
tokens = auth.api.o_auth2_token(
|
|
48
|
+
body: {
|
|
49
|
+
grant_type: "authorization_code",
|
|
50
|
+
code: params[:code],
|
|
51
|
+
redirect_uri: "https://client.example.com/callback",
|
|
52
|
+
client_id: client[:client_id],
|
|
53
|
+
client_secret: client[:client_secret],
|
|
54
|
+
code_verifier: verifier
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
When `resource` is present and valid, access tokens are JWTs. Without `resource`, access tokens are opaque and introspectable.
|
|
60
|
+
|
|
61
|
+
## Routes
|
|
62
|
+
|
|
63
|
+
| Method | Path | Ruby API method |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `GET` | `/.well-known/oauth-authorization-server` | `auth.api.get_o_auth_server_config` |
|
|
66
|
+
| `GET` | `/.well-known/openid-configuration` | `auth.api.get_open_id_config` |
|
|
67
|
+
| `POST` | `/oauth2/register` | `auth.api.register_o_auth_client` |
|
|
68
|
+
| `POST` | `/oauth2/create-client` | `auth.api.create_o_auth_client` |
|
|
69
|
+
| `POST` | `/admin/oauth2/create-client` | `auth.api.admin_create_o_auth_client` |
|
|
70
|
+
| `PATCH` | `/admin/oauth2/update-client` | `auth.api.admin_update_o_auth_client` |
|
|
71
|
+
| `GET` | `/oauth2/get-client?client_id=...` | `auth.api.get_o_auth_client` |
|
|
72
|
+
| `GET` | `/oauth2/get-clients` | `auth.api.get_o_auth_clients` |
|
|
73
|
+
| `POST` | `/oauth2/update-client` | `auth.api.update_o_auth_client` |
|
|
74
|
+
| `POST` | `/oauth2/delete-client` | `auth.api.delete_o_auth_client` |
|
|
75
|
+
| `GET` | `/oauth2/public-client?client_id=...` | `auth.api.get_o_auth_client_public` |
|
|
76
|
+
| `POST` | `/oauth2/public-client-prelogin` | `auth.api.get_o_auth_client_public_prelogin` |
|
|
77
|
+
| `POST` | `/oauth2/client/rotate-secret` | `auth.api.rotate_o_auth_client_secret` |
|
|
78
|
+
| `GET` | `/oauth2/authorize` | `auth.api.o_auth2_authorize` |
|
|
79
|
+
| `POST` | `/oauth2/continue` | `auth.api.o_auth2_continue` |
|
|
80
|
+
| `POST` | `/oauth2/consent` | `auth.api.o_auth2_consent` |
|
|
81
|
+
| `GET` | `/oauth2/get-consent?id=...` | `auth.api.get_o_auth_consent` |
|
|
82
|
+
| `GET` | `/oauth2/get-consents` | `auth.api.get_o_auth_consents` |
|
|
83
|
+
| `POST` | `/oauth2/update-consent` | `auth.api.update_o_auth_consent` |
|
|
84
|
+
| `POST` | `/oauth2/delete-consent` | `auth.api.delete_o_auth_consent` |
|
|
85
|
+
| `POST` | `/oauth2/token` | `auth.api.o_auth2_token` |
|
|
86
|
+
| `POST` | `/oauth2/introspect` | `auth.api.o_auth2_introspect` |
|
|
87
|
+
| `POST` | `/oauth2/revoke` | `auth.api.o_auth2_revoke` |
|
|
88
|
+
| `GET` | `/oauth2/userinfo` | `auth.api.o_auth2_user_info` |
|
|
89
|
+
| `GET`, `POST` | `/oauth2/end-session` | `auth.api.o_auth2_end_session` |
|
|
90
|
+
|
|
91
|
+
Deprecated aliases remain for one minor release: `GET /oauth2/client/:id` -> `/oauth2/get-client`, `GET /oauth2/clients` -> `/oauth2/get-clients`, `PATCH /oauth2/client` -> `/oauth2/update-client`, `DELETE /oauth2/client` -> `/oauth2/delete-client`, `GET /oauth2/client` -> `/oauth2/public-client`, and `GET/PATCH/DELETE /oauth2/consent` plus `GET /oauth2/consents` -> the `get/update/delete/get-consents` consent routes.
|
|
92
|
+
|
|
93
|
+
Admin client routes are server-only. They are available through `auth.api.*` and return `403` through the Rack handler.
|
|
94
|
+
|
|
95
|
+
## Options
|
|
96
|
+
|
|
97
|
+
Common options accepted by `BetterAuth::Plugins.oauth_provider`:
|
|
98
|
+
|
|
99
|
+
- `login_page`
|
|
100
|
+
- `consent_page`
|
|
101
|
+
- `scopes`
|
|
102
|
+
- `claims`
|
|
103
|
+
- `grant_types`
|
|
104
|
+
- `allow_dynamic_client_registration`
|
|
105
|
+
- `allow_unauthenticated_client_registration`
|
|
106
|
+
- `client_registration_default_scopes`
|
|
107
|
+
- `client_registration_allowed_scopes`
|
|
108
|
+
- `store_client_secret`
|
|
109
|
+
- `prefix`
|
|
110
|
+
- `refresh_token_expires_in`
|
|
111
|
+
- `advertised_metadata`
|
|
112
|
+
- `valid_audiences`
|
|
113
|
+
- `custom_token_response_fields`
|
|
114
|
+
- `custom_access_token_claims`
|
|
115
|
+
- `custom_user_info_claims`
|
|
116
|
+
- `pairwise_secret`
|
|
117
|
+
- `signup`
|
|
118
|
+
- `select_account`
|
|
119
|
+
- `post_login`
|
|
120
|
+
- `client_privileges`
|
|
121
|
+
- `rate_limit`
|
|
122
|
+
- `jwks_uri`
|
|
123
|
+
- `disable_jwt_plugin`
|
|
124
|
+
- `store`
|
|
125
|
+
|
|
126
|
+
`rate_limit` accepts per-route overrides:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
rate_limit: {
|
|
130
|
+
token: {window: 60, max: 20},
|
|
131
|
+
authorize: {window: 60, max: 30},
|
|
132
|
+
introspect: {window: 60, max: 100},
|
|
133
|
+
revoke: {window: 60, max: 30},
|
|
134
|
+
register: {window: 60, max: 5},
|
|
135
|
+
userinfo: false
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Use `false` to disable a route-specific rule.
|
|
140
|
+
|
|
141
|
+
## Schema Migration
|
|
142
|
+
|
|
143
|
+
`oauthAccessToken` now uses the upstream canonical columns `token`, `expiresAt`, `scopes`, `clientId`, `sessionId`, `userId`, `referenceId`, and `refreshId`. Legacy `access_token`, `refresh_token`, `access_token_expires_at`, and `scope` columns should be copied forward then dropped. `oauthConsent#consent_given` is also removed; a consent row means consent was granted.
|
|
144
|
+
|
|
145
|
+
For non-Rails SQL apps, run the equivalent of:
|
|
146
|
+
|
|
147
|
+
```sql
|
|
148
|
+
UPDATE better_auth_oauth_access_tokens
|
|
149
|
+
SET token = COALESCE(token, access_token),
|
|
150
|
+
expires_at = COALESCE(expires_at, access_token_expires_at),
|
|
151
|
+
scopes = COALESCE(scopes, scope)
|
|
152
|
+
WHERE token IS NULL OR scopes IS NULL;
|
|
153
|
+
|
|
154
|
+
DELETE FROM better_auth_oauth_consents WHERE consent_given = false;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Then drop the legacy access-token and consent columns. Rails apps using `better_auth-rails` generate migrations from the active plugin schema, so regenerating after this change emits only the canonical columns.
|
|
158
|
+
|
|
159
|
+
## Ruby Adaptations
|
|
160
|
+
|
|
161
|
+
When the JWT plugin is registered, OIDC metadata advertises its configured `jwks.key_pair_config.alg`, defaulting to `EdDSA` like upstream. If `disable_jwt_plugin: true` is set, Ruby intentionally falls back to HS256 ID tokens signed with the Better Auth secret.
|
|
162
|
+
|
|
163
|
+
Route OpenAPI metadata blocks from upstream TypeScript are intentionally not ported into this package. Use the Ruby `open_api` plugin for generated OpenAPI output.
|
|
164
|
+
|
|
165
|
+
The upstream `@better-auth/oauth-provider/client`, React/Solid client plugins, dashboard UI, and browser helpers are not ported. Ruby apps call the JSON endpoints directly or wrap `auth.api.*`.
|
|
166
|
+
|
|
18
167
|
OIDC provider remains a core `better_auth` plugin because upstream still exposes it from `better-auth/plugins`. OAuth provider is the newer standalone provider package.
|