Skip to content

Commit

Permalink
feat: sign in with apple (#1833)
Browse files Browse the repository at this point in the history
Adds an adapter and configuration options for enabling Social Sign In with Apple.

Closes #1782
  • Loading branch information
aeneasr committed Oct 12, 2021
1 parent 198991a commit 16ed123
Show file tree
Hide file tree
Showing 22 changed files with 553 additions and 50 deletions.
77 changes: 77 additions & 0 deletions docs/docs/guides/sign-in-with-github-google-facebook-linkedin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,83 @@ selfservice:
Next, open the login endpoint of the SecureApp and you should see the Yandex
Login option!

## Apple

To set up "Sign in with Apple" you must
[create an app, a service and a private key](https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple#create-an-app-id).

Set the "Redirect URI" to:

```
https://playground.projects.oryapis.com/api/kratos/public/self-service/methods/oidc/callback/apple
```

Due to implementation constraints, the provider ID at the end of this address
cannot be changed.

The pattern of this URL is:

```
http(s)://<domain-of-ory-kratos>:<public-port>/self-service/methods/oidc/callback/<provider-id>
```

The provider ID must point to the provider's ID set in the Ory Kratos
configuration file (explained in further detail at
[OpenID Connect and OAuth2 Credentials](../concepts/credentials/openid-connect-oidc-oauth2.mdx)).

As explained in
[OpenID Connect and OAuth2 Credentials](../concepts/credentials/openid-connect-oidc-oauth2.mdx),
you must also create a Jsonnet code snippet for the provider. Save the code in
`<kratos-directory>/contrib/quickstart/kratos/email-password/oidc.apple.jsonnet`.

```json title="contrib/quickstart/kratos/email-password/oidc.apple.jsonnet"
local claims = {
email_verified: false
} + std.extVar('claims');

{
identity: {
traits: {
// Allowing unverified email addresses enables account
// enumeration attacks, especially if the value is used for
// e.g. verification or as a password login identifier.
//
// Therefore we only return the email if it (a) exists and (b) is marked verified
// by Apple.
[if "email" in claims && claims.email_verified then "email" else null]: claims.email,
},
},
}
```

Now, enable the Apple provider in the Ory Kratos config located at
`<kratos-directory>/contrib/quickstart/kratos/email-password/kratos.yml`.

```yaml title="contrib/quickstart/kratos/email-password/kratos.yml"
# $ kratos -c path/to/my/kratos/config.yml serve
selfservice:
methods:
oidc:
enabled: true
config:
providers:
- id: apple # this is `<provider-id>` in the Authorization callback URL. It should be "apple"
provider: apple
client_id: .... # Replace this with the Services ID provided by Apple
team_id: .... # Replace this with the Team ID provided by Apple
private_key_id: .... # Replace this with the private key identifier generated by Apple
private_key: |
-----BEGIN PRIVATE KEY-----
.... # Replace this by the content of the private key downloaded from Apple
-----END PRIVATE KEY-----
mapper_url: file:///etc/config/kratos/oidc.apple.jsonnet
scope:
- email
```

Next, open the login endpoint of the SecureApp and you should see the Apple
Login option!

## LinkedIn

Connecting with other Social Sign In providers will be very similar to the
Expand Down
138 changes: 115 additions & 23 deletions embedx/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,8 @@
"facebook",
"auth0",
"vk",
"yandex"
"yandex",
"apple"
],
"examples": [
"google"
Expand Down Expand Up @@ -394,6 +395,30 @@
"contoso.onmicrosoft.com"
]
},
"team_id": {
"title": "Apple Developer Team ID",
"description": "Apple Developer Team ID needed for generating a JWT token for client secret",
"type": "string",
"examples": [
"KP76DQS54M"
]
},
"private_key_id": {
"title": "Apple Private Key Identifier",
"description": "Sign In with Apple Private Key Identifier needed for generating a JWT token for client secret",
"type": "string",
"examples": [
"UX56C66723"
]
},
"private_key": {
"title": "Apple Private Key",
"description": "Sign In with Apple Private Key needed for generating a JWT token for client secret",
"type": "string",
"examples": [
"-----BEGIN PRIVATE KEY-----\n........\n-----END PRIVATE KEY-----"
]
},
"requested_claims": {
"$ref": "#/definitions/OIDCClaims"
}
Expand All @@ -403,34 +428,101 @@
"id",
"provider",
"client_id",
"client_secret",
"mapper_url"
],
"if": {
"properties": {
"provider": {
"const": "microsoft"
"allOf": [
{
"if": {
"properties": {
"provider": {
"const": "microsoft"
}
},
"required": [
"provider"
]
},
"then": {
"required": [
"tenant"
]
},
"else": {
"not": {
"properties": {
"tenant": {}
},
"required": [
"tenant"
]
}
}
},
"required": [
"provider"
]
},
"then": {
"required": [
"tenant"
]
},
"else": {
"not": {
"properties": {
"tenant": {}
{
"if": {
"properties": {
"provider": {
"const": "apple"
}
},
"required": [
"provider"
]
},
"required": [
"tenant"
]
"then": {
"not": {
"properties": {
"client_secret": {}
},
"required": [
"client_secret"
]
},
"required": [
"private_key_id",
"private_key",
"team_id"
]
},
"else": {
"required": [
"client_secret"
],
"allOf": [
{
"not": {
"properties": {
"team_id": {}
},
"required": [
"team_id"
]
}
},
{
"not": {
"properties": {
"private_key_id": {}
},
"required": [
"private_key_id"
]
}
},
{
"not": {
"properties": {
"private_key": {}
},
"required": [
"private_key"
]
}
}
]
}
}
}
]
},
"selfServiceHooks": {
"type": "array",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/davidrjonas/semver-cli v0.0.0-20190116233701-ee19a9a0dda6
github.com/fatih/color v1.9.0
github.com/form3tech-oss/jwt-go v3.2.2+incompatible
github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors v1.0.1
github.com/go-openapi/strfmt v0.20.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
Expand Down
49 changes: 26 additions & 23 deletions selfservice/strategy/oidc/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"

"golang.org/x/oauth2"

"github.com/ory/kratos/x"
)

type Provider interface {
Expand All @@ -13,28 +15,29 @@ type Provider interface {
AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption
}

// ConvertibleBoolean is used as Apple casually sends the email_verified field as a string.
type Claims struct {
Issuer string `json:"iss,omitempty"`
Subject string `json:"sub,omitempty"`
Name string `json:"name,omitempty"`
GivenName string `json:"given_name,omitempty"`
FamilyName string `json:"family_name,omitempty"`
LastName string `json:"last_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
Nickname string `json:"nickname,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
Profile string `json:"profile,omitempty"`
Picture string `json:"picture,omitempty"`
Website string `json:"website,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
Gender string `json:"gender,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Zoneinfo string `json:"zoneinfo,omitempty"`
Locale string `json:"locale,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
HD string `json:"hd,omitempty"`
Team string `json:"team,omitempty"`
Issuer string `json:"iss,omitempty"`
Subject string `json:"sub,omitempty"`
Name string `json:"name,omitempty"`
GivenName string `json:"given_name,omitempty"`
FamilyName string `json:"family_name,omitempty"`
LastName string `json:"last_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
Nickname string `json:"nickname,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
Profile string `json:"profile,omitempty"`
Picture string `json:"picture,omitempty"`
Website string `json:"website,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified x.ConvertibleBoolean `json:"email_verified,omitempty"`
Gender string `json:"gender,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Zoneinfo string `json:"zoneinfo,omitempty"`
Locale string `json:"locale,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
HD string `json:"hd,omitempty"`
Team string `json:"team,omitempty"`
}

0 comments on commit 16ed123

Please sign in to comment.