Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: refresh token activation #1795

Merged
merged 4 commits into from May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/docs/apis/openidoauth/endpoints.md
Expand Up @@ -139,6 +139,46 @@ curl --request POST \
--data client_assertion=eyJhbGciOiJSUzI1Ni...
```

### Refresh Token Grant

---

Required request Parameters

| Parameter | Description |
| ------------- | ----------------------------------------------------------------------------------- |
| grant_type | Must be `refresh_token` |
| refresh_token | The refresh_token previously issued in the last auth code or refresh token request. |
| scope | [Scopes](Scopes) you would like to request from ZITADEL for the new access_token. Must be a subset of the scope originally requested by the corresponding auth request. When omitted, the scopes requested by the original auth request will be reused. Scopes are space delimited, e.g. `openid email profile` |

Depending on your authorization method you will have to provide additional parameters or headers:

When using `client_secret_basic`

Send your `client_id` and `client_secret` as Basic Auth Header. Check [Client Secret Basic Auth Method](authn-methods#client-secret-basic) on how to build it correctly.

When using `client_secret_post`

Send your `client_id` and `client_secret` as parameters in the body:

| Parameter | Description |
| ------------- | -------------------------------- |
| client_id | client_id of the application |
| client_secret | client_secret of the application |

When using `none` (PKCE)

Send your `client_id` as parameter in the body. No authentication is required.

When using `private_key_jwt`

Send a client assertion as JWT for us to validate the signature against the registered public key.

| Parameter | Description |
| --------------------- | --------------------------------------------------------------------------------------------------------------- |
| client_assertion | JWT built and signed according to [Using JWTs for Client Authentication](authn-methods#jwt-with-private-key) |
| client_assertion_type | Must be `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |

## introspection_endpoint

[https://api.zitadel.ch/oauth/v2/introspect](https://api.zitadel.ch/oauth/v2/introspect)
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/apis/openidoauth/grant-types.md
Expand Up @@ -12,7 +12,7 @@ For a list of supported or unsupported `Grant Types` please have a look at the t
| Device Authorization | under consideration |
| Implicit | yes |
| JSON Web Token (JWT) Profile | yes |
| Refresh Token | work in progress |
| Refresh Token | yes |
| Resource Owner Password Credentials | no |
| Security Assertion Markup Language (SAML) 2.0 Profile | no |
| Token Exchange | work in progress |
Expand Down
13 changes: 7 additions & 6 deletions docs/docs/apis/openidoauth/scopes.md
Expand Up @@ -6,12 +6,13 @@ ZITADEL supports the usage of scopes as way of requesting information from the I

## Standard Scopes

| Scopes | Example | Description |
|:--------|:----------|------------------------------------------------------|
| openid | `openid` | When using openid connect this is a mandatory scope |
| profile | `profile` | Optional scope to request the profile of the subject |
| email | `email` | Optional scope to request the email of the subject |
| address | `address` | Optional scope to request the address of the subject |
| Scopes | Example | Description |
|:---------------|:-----------------|--------------------------------------------------------------------------------|
| openid | `openid` | When using openid connect this is a mandatory scope |
| profile | `profile` | Optional scope to request the profile of the subject |
| email | `email` | Optional scope to request the email of the subject |
| address | `address` | Optional scope to request the address of the subject |
| offline_access | `offline_access` | Optional scope to request a refresh_token (only possible when using code flow) |

## Custom Scopes

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -16,7 +16,7 @@ require (
github.com/allegro/bigcache v1.2.1
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
github.com/caos/logging v0.0.2
github.com/caos/oidc v0.15.0
github.com/caos/oidc v0.15.1
github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980
github.com/cockroachdb/cockroach-go/v2 v2.1.0
github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -137,8 +137,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
github.com/caos/oidc v0.14.4/go.mod h1:H5Y2zw3YIrWqQOoy0wcmZva2a66bumDyU2iOhXiM9uA=
github.com/caos/oidc v0.15.0 h1:lSykVX6yfUbWpJPAZ9/ZCuowo95h7AgfgPaC15lzf4Y=
github.com/caos/oidc v0.15.0/go.mod h1:JiK5RXSOgag66wiSOMEkS+yS4R46Baz6dGwfr60VfvI=
github.com/caos/oidc v0.15.1 h1:dzMelbk9uYkNTfEy9+273o0fwZTgMSj9eqvS7UtKUpo=
github.com/caos/oidc v0.15.1/go.mod h1:JiK5RXSOgag66wiSOMEkS+yS4R46Baz6dGwfr60VfvI=
github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980 h1:Fz0aYUwGMA2tsu5w7SryqFGjqGClJVHbyhBMT5SXtPU=
github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980/go.mod h1:2I8oiZb5SMRm/qTLvwpSmdV0M6ex8J/UKyxUGfKaqJo=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
Expand Down
25 changes: 25 additions & 0 deletions internal/api/oidc/client_converter.go
Expand Up @@ -61,6 +61,10 @@ func (c *Client) ResponseTypes() []oidc.ResponseType {
return responseTypesToOIDC(c.OIDCResponseTypes)
}

func (c *Client) GrantTypes() []oidc.GrantType {
return grantTypesToOIDC(c.OIDCGrantTypes)
}

func (c *Client) DevMode() bool {
return c.ApplicationView.DevMode
}
Expand Down Expand Up @@ -165,6 +169,27 @@ func responseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType {
}
}

func grantTypesToOIDC(grantTypes []model.OIDCGrantType) []oidc.GrantType {
oidcTypes := make([]oidc.GrantType, len(grantTypes))
for i, t := range grantTypes {
oidcTypes[i] = grantTypeToOIDC(t)
}
return oidcTypes
}

func grantTypeToOIDC(grantType model.OIDCGrantType) oidc.GrantType {
switch grantType {
case model.OIDCGrantTypeAuthorizationCode:
return oidc.GrantTypeCode
case model.OIDCGrantTypeImplicit:
return oidc.GrantTypeImplicit
case model.OIDCGrantTypeRefreshToken:
return oidc.GrantTypeRefreshToken
default:
return oidc.GrantTypeCode
}
}

func removeScopeWithPrefix(scopes []string, scopePrefix ...string) []string {
newScopeList := make([]string, 0)
for _, scope := range scopes {
Expand Down
1 change: 1 addition & 0 deletions internal/api/oidc/op.go
Expand Up @@ -73,6 +73,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, command *command.C
}
copy(config.OPConfig.CryptoKey[:], cryptoKey)
config.OPConfig.CodeMethodS256 = true
config.OPConfig.GrantTypeRefreshToken = true
metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
provider, err := op.NewOpenIDProvider(
ctx,
Expand Down
14 changes: 11 additions & 3 deletions internal/domain/application_oidc.go
Expand Up @@ -190,6 +190,7 @@ func GetOIDCV1Compliance(appType OIDCApplicationType, grantTypes []OIDCGrantType
compliance.NoneCompliant = true
compliance.Problems = append([]string{"Application.OIDC.V1.NoRedirectUris"}, compliance.Problems...)
}
CheckGrantTypes(compliance, grantTypes)
if containsOIDCGrantType(grantTypes, OIDCGrantTypeImplicit) && containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) {
CheckRedirectUrisImplicitAndCode(compliance, appType, redirectUris)
} else {
Expand All @@ -213,6 +214,13 @@ func GetOIDCV1Compliance(appType OIDCApplicationType, grantTypes []OIDCGrantType
return compliance
}

func CheckGrantTypes(compliance *Compliance, grantTypes []OIDCGrantType) {
if containsOIDCGrantType(grantTypes, OIDCGrantTypeRefreshToken) && !containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) {
compliance.NoneCompliant = true
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.GrantType.Refresh.NoAuthCode")
}
}

func GetOIDCV1NativeApplicationCompliance(compliance *Compliance, authMethod OIDCAuthMethodType) {
if authMethod != OIDCAuthMethodTypeNone {
compliance.NoneCompliant = true
Expand All @@ -238,7 +246,7 @@ func CheckRedirectUrisCode(compliance *Compliance, appType OIDCApplicationType,
}
if appType == OIDCApplicationTypeNative && !onlyLocalhostIsHttp(redirectUris) {
compliance.NoneCompliant = true
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Code.RedirectUris.NativeShouldBeHttpLocalhost")
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Native.RedirectUris.MustBeHttpLocalhost")
}
}
if containsCustom(redirectUris) && appType != OIDCApplicationTypeNative {
Expand All @@ -259,7 +267,7 @@ func CheckRedirectUrisImplicit(compliance *Compliance, appType OIDCApplicationTy
if appType == OIDCApplicationTypeNative {
if !onlyLocalhostIsHttp(redirectUris) {
compliance.NoneCompliant = true
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.NativeShouldBeHttpLocalhost")
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Native.RedirectUris.MustBeHttpLocalhost")
}
return
}
Expand All @@ -283,7 +291,7 @@ func CheckRedirectUrisImplicitAndCode(compliance *Compliance, appType OIDCApplic
}
if !onlyLocalhostIsHttp(redirectUris) && appType == OIDCApplicationTypeNative {
compliance.NoneCompliant = true
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.NativeShouldBeHttpLocalhost")
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Native.RedirectUris.MustBeHttpLocalhost")
}
}
if !compliance.NoneCompliant {
Expand Down
6 changes: 5 additions & 1 deletion internal/static/i18n/de.yaml
Expand Up @@ -695,11 +695,15 @@ Application:
RedirectUris:
CustomNotAllowed: Grant Type Implicit erlaubt keine custom Redirect Uris.
HttpNotAllowed: Grant Type Implicit erlaubt keine http Redirect Uris.
NativeShouldBeHttpLocalhost: Grant Type Implicit erlaubt beim Apptype Native http nur mit localhost (http://localhost)
HttpLocalhostOnlyForNative: Http://localhost Redirect Uri ist nur für Native Applikationen erlaubt.
Native:
AuthMethodType:
NotNone: Bei Native Applikationen sollte der AuthMethodType none sein.
RedirectUris:
MustBeHttpLocalhost: Die Weiterleitung muss mit einem eigenen Protokoll, http://127.0.0.1, http://[::1] oder http://localhost beginnen.
UserAgent:
AuthMethodType:
NotNone: Bei einem User Agent sollte der AuthMethodType none sein.
GrantType:
Refresh:
NoAuthCode: Refresh Token nur in Kombination mit Authorization Code erlaubt.
6 changes: 5 additions & 1 deletion internal/static/i18n/en.yaml
Expand Up @@ -696,11 +696,15 @@ Application:
RedirectUris:
CustomNotAllowed: Grant type implicit doesn't allow custom redirect uris
HttpNotAllowed: Grant tpye implicit doesn't allow http redirect uris
NativeShouldBeHttpLocalhost: Grant tpye implicit only allowed http://localhost for native apptype
HttpLocalhostOnlyForNative: Http://localhost redirect uri is only allowed for native applications.
Native:
AuthMethodType:
NotNone: Native applications should have authmethodtype none.
RedirectUris:
MustBeHttpLocalhost: Redirect URIs must begin with your own protocol, http://127.0.0.1, http://[::1] or http://localhost.
UserAgent:
AuthMethodType:
NotNone: User agent app should have authmethodtype none.
GrantType:
Refresh:
NoAuthCode: Refresh Token only allowed in combination with Authorization Code.