I can’t get additional traits like `picture` in my...
# talk-kratos
w
I can’t get additional traits like
picture
in my github social login (the scope is “user”, which should allow getting all user profile info). Here’s my mapper jsonnet and identity schema:
p
Hi @User I don't see any
picture
property being returned from the github OAuth
user
scopes. https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps Maybe check out: https://stackoverflow.com/questions/22932422/get-github-avatar-from-email-or-name
w
Actually the docs mention a section of Kratos code that shows all github traits that should be included in
claims
jsonnet receives and it looks like picture should be included: https://github.com/ory/kratos/blob/v0.2.1-alpha.1/selfservice/strategy/oidc/provider_github.go#L72-L98 . Scope shouldn’t be an issue since github’s User endpoint (which is what the scope “user” grants access to AFAIK) includes
avatar_url
which Kratos code seems to be mapping to claims.Picture?
Am I misunderstanding how Jsonnet claims work? It doesn’t look like I am
p
Ah, yes you are correct. I can also see it is referenced as
picture
. https://github.com/ory/kratos/blob/16463ead91a009f33373150d10095aa3857b38f4/selfservice/strategy/oidc/provider.go#L27 maybe it is a bug somewhere 🤔
w
Right - any suggestions as to how to proceed?
p
I just tested this and it's working for me. Can you show me your kratos configs for oidc? please omit any client_id and secrets
w
Here’s my default schema:
Copy code
{
  "$id": "<https://kratos.sidetrek.com/registration.schema.json>",
  "$schema": "<http://json-schema.org/draft-07/schema#>",
  "title": "Person",
  "type": "object",
  "properties": {
    "traits": {
      "type": "object",
      "properties": {
        "email": {
          "type": "string",
          "format": "email",
          "<http://ory.sh/kratos|ory.sh/kratos>": {
            "credentials": {
              "password": {
                "identifier": true
              }
            }
          }
        },
        "name": {
          "type": "string"
        },
        "picture": {
          "type": "string"
        }
      }
    }
  }
}
kratos.yaml
Copy code
courier:
  smtp:
    connection_uri: smtp://
serve:
  admin:
    base_url: <http://127.0.0.1:4434/>
  public:
    base_url: <http://127.0.0.1:4433/>
    cors:
      enabled: true
      allowed_origins:
        - <http://127.0.0.1:3002>
      allowed_methods:
        - POST
        - GET
        - PUT
        - PATCH
        - DELETE
      allowed_headers:
        - Authorization
        - Cookie
        - Content-Type
      exposed_headers:
        - Content-Type
        - Set-Cookie
identity:
  default_schema_url: file://./default.schema.json
dsn: postgres://
selfservice:
  default_browser_return_url: <https://sidetrek.com>
  whitelisted_return_urls:
    - <https://sidetrek.com>
  flows:
    registration:
      after:
        oidc:
          hooks:
            - hook: session
    logout:
      after:
        default_browser_return_url: '<http://127.0.0.1:3002/login>'
    error:
      ui_url: '<http://127.0.0.1:3002/error>'
  methods:
    oidc:
      enabled: true
      config:
        providers:
          - id: github
            provider: github
            mapper_url: 'file://./oidc.github.jsonnet'
            client_id: ''
            client_secret: ''
            scope:
              - 'user'
oidc.github.jsonnet
Copy code
# claims contains all the data sent by the upstream.
local claims = std.extVar('claims');

{
  identity: {
    traits: {
      // [if std.objectHas(claims, "issuer") then "issuer" else null]: claims.issuer,
      [if std.objectHas(claims, "email") && claims.email_verified then "email" else null]: claims.email,
      [if std.objectHas(claims, "name") then "name" else null]: claims.name,
      [if std.objectHas(claims, "picture") then "picture" else null]: claims.picture,
    },
  },
}
p
try
Copy code
scope:
  - user:email
w
Oh does that scope still give you access to all other traits? I thought that just gives you access to the email
user scope should include user:email scope according to github but I’ll try that
p
it gave me access to the picture, not sure about the name
Copy code
GNU nano 4.8                                                                                                                       oidc.github.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 GitHub.
      [if "email" in claims && claims.email_verified then "email" else null]: claims.email,
      [if "picture" in claims then "picture" else null]: claims.picture,
    },
  },
}
also this is my jsonnet
from the default quickstart
i added the picture part
w
OK let me try it
p
hope this helps, let me know 🙂
w
OK will update you once I try this thanks!
Interesting - it works now. Scope “user” also works FYI. I think my local setup must have had some weird issues (maybe not updating the scope correctly during docker build process?). Anyway, thanks for looking into this!
Since I got you here though one more quick question
For multiple subdomain setup, I specify domain_aliases
For example
Copy code
domain_aliases: [
  {
    match_domain: `<http://sidetrek.com|sidetrek.com>`,
    base_path: '/',
    scheme: 'https',
  },
  {
    match_domain: `<http://staging.sidetrek.com|staging.sidetrek.com>`,
    base_path: '/',
    scheme: 'https',
  },
],
But can I use wild card for this?
Copy code
domain_aliases: [
  {
    match_domain: `<http://sidetrek.com|sidetrek.com>`,
    base_path: '/',
    scheme: 'https',
  },
  {
    match_domain: `*.<http://sidetrek.com|sidetrek.com>`,
    base_path: '/',
    scheme: 'https',
  },
],
Is this possible?
p
why do you need a subdomain wildcard when you can set the cookie for the TLD? or are you doing multi-tenancy?
w
Oh I might have misunderstood the docs then - I just need to make sure cookie sets properly for all subdomains. I thought you need to add these domain aliases if I were to do that. For example, I have
<http://staging.sidetrek.com|staging.sidetrek.com>
and
<http://jhub.sidetrek.com|jhub.sidetrek.com>
- but possibly more things that users can dynamically add like
<http://mlflow.sidetrek.com|mlflow.sidetrek.com>
So I wanted to make sure cookies set properly for all subdomains of the same TLD
I just can’t seem to get the CORS to work:
Copy code
Access to XMLHttpRequest at '<https://kratos.sidetrek.com/self-service/login?flow=60ce0306-a201-4042-8cbe-58e23e7a5ff5>' from origin '<https://auth.sidetrek.com>' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here’s my CORS setting as per the recommendations in the docs:
Copy code
cors: {
  enabled: true,
  allowed_origins: [
    `https://${appApexHostname}`,
    `https://${appWildcardHostname}`,
    // `<https://auth.sidetrek.com>`,
  ],
  allowed_methods: ['POST', 'GET', 'PUT', 'PATCH', 'DELETE'],
  allowed_headers: ['Authorization', 'Cookie', 'Content-Type'],
  exposed_headers: ['Content-Type', 'Set-Cookie'],
},
I’m not even sure if this really is a CORS issue since I seem to be hitting other endpoints fine:
Copy code
GET <https://kratos.sidetrek.com/self-service/login/browser>
This works without issues
So I thought it’s the form submission that’s the issue but it works fine locally
p
Just to clarify, so you have a frontend hosted at https://sidetrek.com and you have your backend kratos service on https://kratos.sidetrek.com? You want a cookie to be set on sidetrek.com and all sub-domains, e.g. something.sidetrek.com also gets added to the session cookie? I'm not sure what your allowed_origins are, but you would need a https://sidetrek.com and a https://*.sidetrek.com for your subdomains.