Commit Graph

156 Commits

Author SHA1 Message Date
Patrik a47e39513f
test: parallelize and improve (#3989) 2025-05-15 15:24:56 +02:00
Patrik cc92fea45f
chore: bump dependencies and move tools (#3968) 2025-03-28 12:42:50 +01:00
Nikos Sklikas 5215d2482a
feat: implement RFC 8628 (#3912)
This patch introduces the OAuth 2.0 Device Authorization Grant to Ory
Hydra. The OAuth 2.0 device authorization grant is designed for
Internet-connected devices that either lack a browser to perform a
user-agent-based authorization or are input constrained to the extent
that requiring the user to input text in order to authenticate during
the authorization flow is impractical. It enables OAuth clients on such
devices (like smart TVs, media consoles, digital picture frames, and
printers) to obtain user authorization to access protected resources by
using a user agent on a separate device.

The OAuth 2.0 Device Authorization Grant may also become relevant for AI
Agent authentication flows and is generally an amazing step and
innovation for this project.

A very special thanks goes to @nsklikas from
[Canonical](https://canonical.com), @supercairos from
[shadow.tech](https://shadow.tech) and @BuzzBumbleBee.

For more details, please check out the documentation
(https://github.com/ory/docs/pull/2026)

To implement this feature, you will need to implement two additional
screens in your login and consent application. A reference
implementation can be found
[here](99ca6ad544/src/routes/device.ts).

Closes #3851
Closes #3252
Closes #3230
Closes #2416
2025-02-26 13:41:41 +01:00
Arne Luenser 5d8635c943
fix: revoke by consent request ID (#3947)
This is a follow-up to #3932.

This makes several improvements, chiefly restoring backwards
compatibility to Hydra before #3932. We now return both the `challenge`
as well as the `consent_request_id` from our APIs and distinguish
between them clearly.

Closes #3941
2025-02-20 19:41:41 +01:00
Arne Luenser 4a40193f24
feat: revoke token chain by consent challenge ID (#3932)
This change adds the ability to revoke token chains by "consent
challenge ID".

## "Consent sessions"

Each time the user goes through a `GET
/oauth2/auth?response_type=code&...` auth code flow, we persist a new
"consent session" to the database.

This is independent of whether the user has previously logged in and/or
granted consent, or whether the user was actively asked to grant consent
by the consent app. A successful journey through the auth code flow
results in a new "consent session".

This consent session is uniquely identified by its "consent challenge
ID". This ID is obtained from the [`GET
/admin/oauth2/auth/requests/consent?consent_challenge=...`](https://www.ory.sh/docs/reference/api#tag/oAuth2/operation/getOAuth2ConsentRequest)
API. Note that it is not the same as the `consent_challenge=...` query
parameter!

Any access and refresh tokens obtained from a token exchange following
that particular user journey are bound to that consent session.

We call the totality of all refresh+access tokens derived from a
particular consent session a "token chain".

## Token revocation

Revoking an access token (AT) is simple: send the AT to `/oauth2/revoke`
and it is revoked. If this AT was derived from a refresh token (RT), the
parent RT is not revoked.

Revoking a refresh token (RT) also revokes associated access tokens.

## Revocation by consent challenge ID

During an authorization code flow, save the consent challenge ID into
the access token session data:

```
GET /admin/oauth2/auth/requests/consent?consent_challenge=abcdef
```
Response:
```
{
  "acr": ...,
  "challenge": "G_TIM3XABG14UwIgDoT1DRfipjhC1uix" # <- this is the ID we need
  ...
}
```

Accept the consent request:
```
PUT /admin/oauth2/auth/requests/consent/accept?consent_challenge=abcdef
{
  "remember": true,
  "remember_for": 3600,
  "session": {
    "access_token": {
      "ccid": "G_TIM3XABG14UwIgDoT1DRfipjhC1uix"
    }
  },
  ...
}
```

To revoke the token chain associated with this consent challenge ID, use

```
POST admin/oauth2/auth/sessions/consent?consent_challenge_id=G_TIM3XABG14UwIgDoT1DRfipjhC1uix
```
2025-02-11 12:12:12 +01:00
hackerman 0a6c966206
feat: handle concurrent refreshes and improve graceful refreshing (#3895)
This patch improves Ory Hydra's ability to deal with refresh flows which, for example, concurrently refresh the same token. Furthermore, graceful token refresh has been improved to handle a variety of edge cases and scenarios.

Additionally, serializability errors in CockroachDB are now correctly retried.

See https://github.com/ory-corp/cloud/issues/7311
Closes https://github.com/ory/hydra/pull/3895
2024-12-17 09:57:05 +01:00
hackerman 5caa6293b1
fix: require `redirect_uri` in openid requests (#3900)
Resolves a deviation from the OpenID Connect spec, where the `redirect_uri` was not required when performing flows with `scope=openid`.

BREAKING CHANGE: Going forward, OAuth2 Clients requesting an OpenID Connect flow **must** include the `redirect_uri` parameter or the request will be rejected.
2024-12-04 11:14:14 +01:00
hackerman e278b405e5
feat: graceful refresh token rotation (#3860)
This patch adds a configuration flag which enables graceful refresh token rotation. Previously, refresh tokens could only be used once. On reuse, all tokens of that chain would be revoked.

This is particularly challenging in environments, where it's difficult to make guarantees on synchronization. This could lead to refresh tokens being sent twice due to some parallel execution.

To resolve this, refresh tokens can now be graceful by changing `oauth2.grant.refresh_token.grace_period=10s` (example value). During this time, a refresh token can be used multiple times to generate new refresh, ID, and access tokens.

All tokens will correctly be invalidated, when the refresh token is re-used after the grace period expires, or when the delete consent endpoint is used.

Closes #1831 #3770
2024-10-21 11:30:02 +02:00
hackerman 56fc3da629
feat: remove unused indices (#3859) 2024-10-14 12:12:16 +02:00
Patrik 477abaeb7d
chore: bump dependencies and generate internal SDK aligned with the published SDK (#3807) 2024-07-31 13:26:57 +02:00
hackerman 89323e24de
fix: upgrade fosite and improve webhook integration (#3727) 2024-03-13 12:03:40 +01:00
Henning Perl 1a40833e2c
fix: handle token hook auth config (#3677)
* fix: handle token hook auth config

* fix: bump golangci-lint

---------

Co-authored-by: Arne Luenser <arne.luenser@ory.sh>
2023-12-18 15:48:40 +01:00
Henning Perl 5f41949ad2
feat: remove login session cookie during consent flow (#3667) 2023-11-15 10:05:49 +01:00
Henning Perl 19857d20b1
feat: add prompt=registration (#3636)
Ory Hydra now supports a `registration` value for the `prompt` parameter of
the authorization request. When specifying `prompt=registration`, Ory Hydra
will redirect the user to the URL found under `urls.registration`
(instead of `urls.login`).
2023-09-29 10:01:35 +02:00
Patrik 5c8e7923ed
feat: add authentication options to hooks (#3633) 2023-09-25 11:09:43 +02:00
Patrik 5dd7d306ba
feat: re-enable legacy client IDs (#3628)
This patch changes the primary key of the `hydra_client` table. We do not expect issues, as that table is probably not overly huge in any deployment. We do however highly recommend to test the migration performance on a staging environment with a similar database setup.
2023-09-19 11:20:23 +02:00
Henning Perl 0176adc178
fix: verifiable credentials JWT format (#3614) 2023-08-23 17:19:32 +02:00
Henning Perl 9f1c8d1920
fix: add kid to verifiable credential header (#3606) 2023-08-16 14:12:43 +02:00
Arne Luenser 1d73d83eb0
fix: reject invalid JWKS in client configuration / dependency cleanup and bump (#3603) 2023-08-11 16:33:22 +02:00
Henning Perl 219a7c068f
feat: add support for OIDC VC (#3575)
This adds initial support for issuing verifiable credentials
as specified in https://openid.net/specs/openid-connect-userinfo-vc-1_0.html.

Because the spec is still in draft, public identifiers are
suffixed with `draft_00`.
2023-08-04 10:57:36 +02:00
Henning Perl f29fe3af97
feat: stateless authorization code flow (#3515)
This patch optimizes the performance of authorization code grant flows by minimizing the number of database queries. We acheive this by storing the flow in an AEAD-encoded cookie and AEAD-encoded request parameters for the authentication and consent screens. 

BREAKING CHANGE:

* The client that is used as part of the authorization grant flow is stored in the AEAD-encoding. Therefore, running flows will not observe updates to the client after they were started.
* Because the login and consent challenge values now include the AEAD-encoded flow, their size increased to around 1kB for a flow without any metadata (and increases linearly with the amount of metadata). Please adjust your ingress / gateway accordingly.
2023-06-12 20:27:00 +02:00
Serhii Halchenko 9bdf225d8f
feat: add token request hooks for all grant types (#3427)
Added a generic token hook that is called for all grant types and includes `payload` with a single allowed value - `assertion` to cover the `jwt-bearer` grant type customization.

The existing `refresh token hook` is left unchanged and is considered to be deprecated in favor of the new hook logic. The `refresh token hook` will at some point be removed.

Closes #3244
Closes https://github.com/ory/fosite/issues/729
2023-03-26 12:35:52 +02:00
Arne Luenser f56e5fad74 fix: append /v2 to module path 2023-01-28 08:40:41 +01:00
Arne Luenser 488f930e4f fix: clean up unused code 2023-01-28 08:40:41 +01:00
hackerman c54b9dbf9a
fix: add v2 suffix (#3340) 2022-11-05 17:53:04 +02:00
Kevin Goslar d768cf6580
docs: standardize license headers (#3216) 2022-11-03 10:10:12 -05:00
aeneasr e800002d09 refactor(sdk): consent SDK
BREAKING CHANGE: SDK naming has changed for the following operations:

```patch
ory.
-   V0alpha2Api.AdminRevokeOAuth2ConsentSessions(cmd.Context()).
+   OAuth2Api.RevokeOAuth2ConsentSessions(context.Background()).
    Client(clientId).Execute()

ory.
-   V0alpha2Api.AdminListOAuth2SubjectConsentSessions(cmd.Context(), id).
+   OAuth2Api.RevokeOAuth2ConsentSessions(context.Background()).
    Client(clientId).Execute()

ory.
-   V0alpha2Api.AdminListOAuth2SubjectConsentSessions(context.Background()).
+   OAuth2Api.ListOAuth2ConsentSessions(context.Background()).
    Subject(subjectId).Execute()

ory.
-   V0alpha2Api.AdminRevokeOAuth2LoginSessions(context.Background()).
+   OAuth2Api.RevokeOAuth2LoginSessions(context.Background()).
    Subject(subjectId).Execute()

ory.
-   V0alpha2Api.AdminGetOAuth2LoginRequest(context.Background()).
+   OAuth2Api.GetOAuth2LoginRequest(context.Background()).
    LoginChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminAcceptOAuth2LoginRequest(context.Background()).
+   OAuth2Api.AcceptOAuth2LoginRequest(context.Background()).
    AcceptOAuth2LoginRequest(body).
    LoginChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminRejectOAuth2LoginRequest(context.Background()).
+   OAuth2Api.RejectOAuth2LoginRequest(context.Background()).
    RejectOAuth2Request(body).
    LoginChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminGetOAuth2ConsentRequest(context.Background()).
+   OAuth2Api.GetOAuth2ConsentRequest(context.Background()).
    ConsentChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminAcceptOAuth2ConsentRequest(context.Background()).
+   OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()).
    AcceptOAuth2ConsentRequest(body).
    ConsentChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminRejectOAuth2ConsentRequest(context.Background()).
+   OAuth2Api.RejectOAuth2ConsentRequest(context.Background()).
    RejectOAuth2Request().
    ConsentChallenge(challenge).Execute()

ory.
-   V0alpha2Api.AdminAcceptOAuth2LogoutRequest(context.Background()).
+   OAuth2Api.AcceptOAuth2LogoutRequest(context.Background()).
    LogoutChallenge(challenge).
    Execute()

ory.
-   V0alpha2Api.AdminRejectOAuth2LogoutRequest(context.Background()).
+   OAuth2Api.RejectOAuth2LogoutRequest(context.Background()).
    LogoutChallenge(challenge).
    Execute()

ory.
    V0alpha2Api.AdminGetOAuth2LogoutRequest(context.Background()).
+   OAuth2Api.GetOAuth2LogoutRequest(context.Background()).
    LogoutChallenge(challenge).
    Execute()

- var AlreadyHandledError HandledOAuth2LoginRequest
+ var AlreadyHandledError ErrorOAuth2LoginRequestAlreadyHandled

- var AlreadyHandledError HandledOAuth2LoginRequest
+ var AlreadyHandledError ErrorOAuth2ConsentRequestAlreadyHandled

- var OAuth2SuccessResponse SuccessfulOAuth2RequestResponse
+ var OAuth2SuccessResponse OAuth2RedirectTo
```
2022-10-11 17:01:24 +02:00
aeneasr cb742ad0d6 refactor(sdk): rename oauth2 client operations and payloads
BREAKING CHANGE: The SDK API for the following has changed:

```patch
// Go example
ory.
-   V0alpha2Api.AdminUpdateOAuth2Client(cmd.Context(), id)
+   Oauth2Api.SetOAuth2Client(cmd.Context(), id).
    OAuth2Client(client).Execute()

ory.
-   V0alpha2Api.AdminGetOAuth2Client(cmd.Context(), id).
+   Oauth2Api.GetOAuth2Client(cmd.Context(), id).
    Execute()

ory.
-   V0alpha2Api.AdminDeleteOAuth2Client(cmd.Context(), id).
+   Oauth2Api.DeleteOAuth2Client(cmd.Context(), id).
    Execute()

ory.
-   V0alpha2Api.AdminCreateOAuth2Client(cmd.Context()).
+   Oauth2Api.CreateOAuth2Client(cmd.Context()).
    OAuth2Client(client).Execute()

ory.
-   V0alpha2Api.DynamicClientRegistrationGetOAuth2Client(cmd.Context(), id).
+   OidcApi.GetOidcDynamicClient(cmd.Context(), id).
    Execute()

ory.
-   V0alpha2Api.DynamicClientRegistrationGetOAuth2Client(cmd.Context()).
+   OidcApi.CreateOidcDynamicClient(cmd.Context()).
    OAuth2Client(client).Execute()

ory.
-   V0alpha2Api.DynamicClientRegistrationDeleteOAuth2Client(cmd.Context()).
+   OidcApi.DeleteOidcDynamicClient(cmd.Context()).
    OAuth2Client(client).Execute()

ory.
-   V0alpha2Api.DynamicClientRegistrationUpdateOAuth2Client(cmd.Context(), id).
+   OidcApi.SetOidcDynamicClient(cmd.Context(), id).
    Execute()
```
2022-10-11 17:01:24 +02:00
aeneasr da0feb7554 chore: format 2022-09-07 08:10:31 +02:00
Ferdynand Naczynski ac279c38f7 chore: change metric name and make Go 1.19 compatible (#3223) 2022-09-07 08:10:31 +02:00
aeneasr a364db4ff2 fix: move to v0alpha2 api spec 2022-09-07 08:10:31 +02:00
aeneasr dc11913681 chore: code review 2022-09-07 08:10:31 +02:00
Grant Zvolsky 51600f499d test: fix a flaky test 2022-09-07 08:10:31 +02:00
Grant Zvolský 9ef671f284 feat: custom client token ttl (#3206)
This change introduces a new endpoint that allows you to control how long client tokens last. Now you can configure the lifespan for each valid combination of Client, GrantType, and TokenType.

See #3157

Co-authored-by: aeneasr <3372410+aeneasr@users.noreply.github.com>
Co-authored-by: Andreas Bucksteeg <andreas@bucksteeg.de>
2022-09-07 08:10:31 +02:00
aeneasr 937e6baabf fix: resolve internal SDK regressions 2022-09-07 08:10:31 +02:00
Grant Zvolsky 53d225a980 refactor: finalize consent SDK methods 2022-09-07 08:10:31 +02:00
aeneasr 34dfc0fe57 unstaged - refactor sdk use across the board 2022-09-07 08:10:31 +02:00
Grant Zvolsky 0752721dd8 refactor(client): rename SDK methods and introduce `/admin` prefix
BREAKING CHANGE: This release updates SDK services from `public` and `admin` to `v2`. Methods exposed at the admin interface are now prefixed with `admin` (e.g. `adminCreateOAuth2Client`). Administrative endpoints now have an `/admin` prefix (e.g. `POST /admin/clients`). Existing administrative endpoints will redirect to this new prefixed path for backwards compatibility.
2022-09-07 08:10:31 +02:00
aeneasr ddba42f498 feat: support alternate hashing algorithms for client secrets
This patch adds support for hashing client secrets using pbkdf2 instead of bcrypt, which might be a more appropriate algorithm in certain settings. As we assume that most environments fall in this category, we also changed the default to pbkdf2 with 25.000 rounds (roughly 1-3ms per hash on an Apple M1 Max core).

High hash costs are needed when hashing user-chosen passwords, as users often reuse passwords across sites. A high hash cost will make it much harder for the attacker to guess the user-chosen password and try using it on other sites (e.g. Google).

As most client secrets are auto-generated, using high hash costs is not useful. The password (OAuth2 Client Secret) is not user chosen and unlikely to be reused. As such, there is little point in using excessive hash costs to protect users. High hash costs in a system like Ory Hydra will cause high CPU costs from mostly automated traffic (OAuth2 Client interactions). It has also been a point of critizism from some who wish for better RPS on specific endpoints.

Other systems like Keycloak do not [hash client secrets at all](https://groups.google.com/g/keycloak-dev/c/TmsNfnol0_g), referencing more secure authentication mechanisms such as assertion-based client authentication.

We and the IETF disagree though, as [rfc6819#section-5.1.4.1.3](https://datatracker.ietf.org/doc/html/rfc6819#section-5.1.4.1.3) states:

> The authorization server should not store credentials in clear text.
   Typical approaches are to store hashes instead or to encrypt
   credentials.  If the credential lacks a reasonable entropy level
   (because it is a user password), an additional salt will harden the
   storage to make offline dictionary attacks more difficult.

For that reason, cleartext storage of client secrets is not going to be supported.

BREAKING CHANGE: This change is backwards compatible, but changes the default hashing algorithm to PBKDF2. To keep using BCrypt for hashing new OAuth2 Client Secrets set the following configuration option in your configuration file:

```
oauth2:
  hashers:
    algorithm: bcrypt
```
2022-09-07 08:10:31 +02:00
aeneasr 5835ede15c chore: update fosite dependency 2022-09-07 08:10:31 +02:00
aeneasr 1100aba1e1 test: fix flaky equal check 2022-09-07 08:10:31 +02:00
aeneasr 82ba44672a chore: update formatter and formatting 2022-09-07 08:10:31 +02:00
aeneasr 2c4615cea9 test: fix flaky equal check 2022-09-07 08:10:31 +02:00
aeneasr 9a4f9e9993 fix: client specific CORS
Closes #1754
2022-09-07 08:10:31 +02:00
aeneasr 4002224439 refactor(client): make OAuth2 Client IDs system-chosen and immutable
BREAKING CHANGE: To improve security and scalability (in particular sharding), OAuth 2.0 Client IDs can no longer be chosen but are always assigned a random generated UUID V4. OAuth 2.0 Clients created with custom IDs before the v2.0 release will continue working with their legacy Client ID in Ory Hydra v2.x.

Additionally, the `hydra create client` command no longer supports flag `--id` and flag `--callbacks` has been renamed to `--redirect-uris`.

Closes #2911
2022-09-07 08:10:31 +02:00
Zach Abney afa2ea0303 feat: add ability to allow token refresh from hook without overriding the session claims (#3146)
Closes #3082
2022-09-07 08:10:31 +02:00
aeneasr bbe0406df6 feat: config hot reloading architecture 2022-09-07 08:10:31 +02:00
Grant Zvolský 1d9891dcf1 fix: use StringSliceJSONFormat instead of StringSlicePipeDelimiter (#3112)
Closes https://github.com/ory/hydra/issues/2859
2022-09-07 08:10:31 +02:00
Grant Zvolsky 8e961d0eb3 code review 2022-09-07 08:10:31 +02:00
Grant Zvolsky 00490cbbc5 code review: generate first NID randomly; add/update tests; fix db-diff 2022-09-07 08:10:31 +02:00